Coverage Report

Created: 2026-08-14 20:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/tmp/bitcoin/src/script/miniscript.h
Line
Count
Source
1
// Copyright (c) 2019-present The Bitcoin Core developers
2
// Distributed under the MIT software license, see the accompanying
3
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5
#ifndef BITCOIN_SCRIPT_MINISCRIPT_H
6
#define BITCOIN_SCRIPT_MINISCRIPT_H
7
8
#include <consensus/consensus.h>
9
#include <crypto/hex_base.h>
10
#include <policy/policy.h>
11
#include <script/interpreter.h>
12
#include <script/parsing.h>
13
#include <script/script.h>
14
#include <serialize.h>
15
#include <util/check.h>
16
#include <util/strencodings.h>
17
#include <util/string.h>
18
#include <util/vector.h>
19
20
#include <algorithm>
21
#include <concepts>
22
#include <cstdint>
23
#include <cstdlib>
24
#include <functional>
25
#include <memory>
26
#include <optional>
27
#include <set>
28
#include <span>
29
#include <stdexcept>
30
#include <string>
31
#include <string_view>
32
#include <tuple>
33
#include <utility>
34
#include <variant>
35
#include <vector>
36
37
namespace miniscript {
38
39
/** This type encapsulates the miniscript type system properties.
40
 *
41
 * Every miniscript expression is one of 4 basic types, and additionally has
42
 * a number of boolean type properties.
43
 *
44
 * The basic types are:
45
 * - "B" Base:
46
 *   - Takes its inputs from the top of the stack.
47
 *   - When satisfied, pushes a nonzero value of up to 4 bytes onto the stack.
48
 *   - When dissatisfied, pushes a 0 onto the stack.
49
 *   - This is used for most expressions, and required for the top level one.
50
 *   - For example: older(n) = <n> OP_CHECKSEQUENCEVERIFY.
51
 * - "V" Verify:
52
 *   - Takes its inputs from the top of the stack.
53
 *   - When satisfied, pushes nothing.
54
 *   - Cannot be dissatisfied.
55
 *   - This can be obtained by adding an OP_VERIFY to a B, modifying the last opcode
56
 *     of a B to its -VERIFY version (only for OP_CHECKSIG, OP_CHECKSIGVERIFY,
57
 *     OP_NUMEQUAL and OP_EQUAL), or by combining a V fragment under some conditions.
58
 *   - For example vc:pk_k(key) = <key> OP_CHECKSIGVERIFY
59
 * - "K" Key:
60
 *   - Takes its inputs from the top of the stack.
61
 *   - Becomes a B when followed by OP_CHECKSIG.
62
 *   - Always pushes a public key onto the stack, for which a signature is to be
63
 *     provided to satisfy the expression.
64
 *   - For example pk_h(key) = OP_DUP OP_HASH160 <Hash160(key)> OP_EQUALVERIFY
65
 * - "W" Wrapped:
66
 *   - Takes its input from one below the top of the stack.
67
 *   - When satisfied, pushes a nonzero value (like B) on top of the stack, or one below.
68
 *   - When dissatisfied, pushes 0 op top of the stack or one below.
69
 *   - Is always "OP_SWAP [B]" or "OP_TOALTSTACK [B] OP_FROMALTSTACK".
70
 *   - For example sc:pk_k(key) = OP_SWAP <key> OP_CHECKSIG
71
 *
72
 * There are type properties that help reasoning about correctness:
73
 * - "z" Zero-arg:
74
 *   - Is known to always consume exactly 0 stack elements.
75
 *   - For example after(n) = <n> OP_CHECKLOCKTIMEVERIFY
76
 * - "o" One-arg:
77
 *   - Is known to always consume exactly 1 stack element.
78
 *   - Conflicts with property 'z'
79
 *   - For example sha256(hash) = OP_SIZE 32 OP_EQUALVERIFY OP_SHA256 <hash> OP_EQUAL
80
 * - "n" Nonzero:
81
 *   - For every way this expression can be satisfied, a satisfaction exists that never needs
82
 *     a zero top stack element.
83
 *   - Conflicts with property 'z' and with type 'W'.
84
 * - "d" Dissatisfiable:
85
 *   - There is an easy way to construct a dissatisfaction for this expression.
86
 *   - Conflicts with type 'V'.
87
 * - "u" Unit:
88
 *   - In case of satisfaction, an exact 1 is put on the stack (rather than just nonzero).
89
 *   - Conflicts with type 'V'.
90
 *
91
 * Additional type properties help reasoning about nonmalleability:
92
 * - "e" Expression:
93
 *   - This implies property 'd', but the dissatisfaction is nonmalleable.
94
 *   - This generally requires 'e' for all subexpressions which are invoked for that
95
 *     dissatisfaction, and property 'f' for the unexecuted subexpressions in that case.
96
 *   - Conflicts with type 'V'.
97
 * - "f" Forced:
98
 *   - Dissatisfactions (if any) for this expression always involve at least one signature.
99
 *   - Is always true for type 'V'.
100
 * - "s" Safe:
101
 *   - Satisfactions for this expression always involve at least one signature.
102
 * - "m" Nonmalleable:
103
 *   - For every way this expression can be satisfied (which may be none),
104
 *     a nonmalleable satisfaction exists.
105
 *   - This generally requires 'm' for all subexpressions, and 'e' for all subexpressions
106
 *     which are dissatisfied when satisfying the parent.
107
 *
108
 * One type property is an implementation detail:
109
 * - "x" Expensive verify:
110
 *   - Expressions with this property have a script whose last opcode is not EQUAL, CHECKSIG, or CHECKMULTISIG.
111
 *   - Not having this property means that it can be converted to a V at no cost (by switching to the
112
 *     -VERIFY version of the last opcode).
113
 *
114
 * Five more type properties for representing timelock information. Spend paths
115
 * in miniscripts containing conflicting timelocks and heightlocks cannot be spent together.
116
 * This helps users detect if miniscript does not match the semantic behaviour the
117
 * user expects.
118
 * - "g" Whether the branch contains a relative time timelock
119
 * - "h" Whether the branch contains a relative height timelock
120
 * - "i" Whether the branch contains an absolute time timelock
121
 * - "j" Whether the branch contains an absolute height timelock
122
 * - "k"
123
 *   - Whether all satisfactions of this expression don't contain a mix of heightlock and timelock
124
 *     of the same type.
125
 *   - If the miniscript does not have the "k" property, the miniscript template will not match
126
 *     the user expectation of the corresponding spending policy.
127
 * For each of these properties the subset rule holds: an expression with properties X, Y, and Z, is also
128
 * valid in places where an X, a Y, a Z, an XY, ... is expected.
129
*/
130
class Type {
131
    //! Internal bitmap of properties (see ""_mst operator for details).
132
    uint32_t m_flags;
133
134
    //! Internal constructor used by the ""_mst operator.
135
15.2M
    explicit constexpr Type(uint32_t flags) : m_flags(flags) {}
136
137
public:
138
    //! The only way to publicly construct a Type is using this literal operator.
139
    friend consteval Type operator""_mst(const char* c, size_t l);
140
141
    //! Compute the type with the union of properties.
142
7.60M
    constexpr Type operator|(Type x) const { return Type(m_flags | x.m_flags); }
143
144
    //! Compute the type with the intersection of properties.
145
7.56M
    constexpr Type operator&(Type x) const { return Type(m_flags & x.m_flags); }
146
147
    //! Check whether the left hand's properties are superset of the right's (= left is a subtype of right).
148
135M
    constexpr bool operator<<(Type x) const { return (x.m_flags & ~m_flags) == 0; }
149
150
    //! Comparison operator to enable use in sets/maps (total ordering incompatible with <<).
151
0
    constexpr bool operator<(Type x) const { return m_flags < x.m_flags; }
152
153
    //! Equality operator.
154
2.70M
    constexpr bool operator==(Type x) const { return m_flags == x.m_flags; }
155
156
    //! The empty type if x is false, itself otherwise.
157
97.6k
    constexpr Type If(bool x) const { return Type(x ? m_flags : 0); }
158
};
159
160
//! Literal operator to construct Type objects.
161
inline consteval Type operator""_mst(const char* c, size_t l)
162
{
163
    Type typ{0};
164
165
    for (const char *p = c; p < c + l; p++) {
166
        typ = typ | Type(
167
            *p == 'B' ? 1 << 0 : // Base type
168
            *p == 'V' ? 1 << 1 : // Verify type
169
            *p == 'K' ? 1 << 2 : // Key type
170
            *p == 'W' ? 1 << 3 : // Wrapped type
171
            *p == 'z' ? 1 << 4 : // Zero-arg property
172
            *p == 'o' ? 1 << 5 : // One-arg property
173
            *p == 'n' ? 1 << 6 : // Nonzero arg property
174
            *p == 'd' ? 1 << 7 : // Dissatisfiable property
175
            *p == 'u' ? 1 << 8 : // Unit property
176
            *p == 'e' ? 1 << 9 : // Expression property
177
            *p == 'f' ? 1 << 10 : // Forced property
178
            *p == 's' ? 1 << 11 : // Safe property
179
            *p == 'm' ? 1 << 12 : // Nonmalleable property
180
            *p == 'x' ? 1 << 13 : // Expensive verify
181
            *p == 'g' ? 1 << 14 : // older: contains relative time timelock   (csv_time)
182
            *p == 'h' ? 1 << 15 : // older: contains relative height timelock (csv_height)
183
            *p == 'i' ? 1 << 16 : // after: contains time timelock   (cltv_time)
184
            *p == 'j' ? 1 << 17 : // after: contains height timelock   (cltv_height)
185
            *p == 'k' ? 1 << 18 : // does not contain a combination of height and time locks
186
            (throw std::logic_error("Unknown character in _mst literal"), 0)
187
        );
188
    }
189
190
    return typ;
191
}
192
193
using Opcode = std::pair<opcodetype, std::vector<unsigned char>>;
194
195
template<typename Key> class Node;
196
197
//! Unordered traversal of a miniscript node tree.
198
template <typename Key, std::invocable<const Node<Key>&> Fn>
199
void ForEachNode(const Node<Key>& root, Fn&& fn)
200
797
{
201
797
    std::vector<std::reference_wrapper<const Node<Key>>> stack{root};
202
996k
    while (!stack.empty()) {
203
995k
        const Node<Key>& node = stack.back();
204
995k
        std::invoke(fn, node);
205
995k
        stack.pop_back();
206
995k
        for (const auto& sub : node.Subs()) {
207
994k
            stack.emplace_back(sub);
208
994k
        }
209
995k
    }
210
797
}
211
212
//! The different node types in miniscript.
213
enum class Fragment {
214
    JUST_0,    //!< OP_0
215
    JUST_1,    //!< OP_1
216
    PK_K,      //!< [key]
217
    PK_H,      //!< OP_DUP OP_HASH160 [keyhash] OP_EQUALVERIFY
218
    OLDER,     //!< [n] OP_CHECKSEQUENCEVERIFY
219
    AFTER,     //!< [n] OP_CHECKLOCKTIMEVERIFY
220
    SHA256,    //!< OP_SIZE 32 OP_EQUALVERIFY OP_SHA256 [hash] OP_EQUAL
221
    HASH256,   //!< OP_SIZE 32 OP_EQUALVERIFY OP_HASH256 [hash] OP_EQUAL
222
    RIPEMD160, //!< OP_SIZE 32 OP_EQUALVERIFY OP_RIPEMD160 [hash] OP_EQUAL
223
    HASH160,   //!< OP_SIZE 32 OP_EQUALVERIFY OP_HASH160 [hash] OP_EQUAL
224
    WRAP_A,    //!< OP_TOALTSTACK [X] OP_FROMALTSTACK
225
    WRAP_S,    //!< OP_SWAP [X]
226
    WRAP_C,    //!< [X] OP_CHECKSIG
227
    WRAP_D,    //!< OP_DUP OP_IF [X] OP_ENDIF
228
    WRAP_V,    //!< [X] OP_VERIFY (or -VERIFY version of last opcode in X)
229
    WRAP_J,    //!< OP_SIZE OP_0NOTEQUAL OP_IF [X] OP_ENDIF
230
    WRAP_N,    //!< [X] OP_0NOTEQUAL
231
    AND_V,     //!< [X] [Y]
232
    AND_B,     //!< [X] [Y] OP_BOOLAND
233
    OR_B,      //!< [X] [Y] OP_BOOLOR
234
    OR_C,      //!< [X] OP_NOTIF [Y] OP_ENDIF
235
    OR_D,      //!< [X] OP_IFDUP OP_NOTIF [Y] OP_ENDIF
236
    OR_I,      //!< OP_IF [X] OP_ELSE [Y] OP_ENDIF
237
    ANDOR,     //!< [X] OP_NOTIF [Z] OP_ELSE [Y] OP_ENDIF
238
    THRESH,    //!< [X1] ([Xn] OP_ADD)* [k] OP_EQUAL
239
    MULTI,     //!< [k] [key_n]* [n] OP_CHECKMULTISIG (only available within P2WSH context)
240
    MULTI_A,   //!< [key_0] OP_CHECKSIG ([key_n] OP_CHECKSIGADD)* [k] OP_NUMEQUAL (only within Tapscript ctx)
241
    // AND_N(X,Y) is represented as ANDOR(X,Y,0)
242
    // WRAP_T(X) is represented as AND_V(X,1)
243
    // WRAP_L(X) is represented as OR_I(0,X)
244
    // WRAP_U(X) is represented as OR_I(X,0)
245
};
246
247
enum class Availability {
248
    NO,
249
    YES,
250
    MAYBE,
251
};
252
253
enum class MiniscriptContext {
254
    P2WSH,
255
    TAPSCRIPT,
256
};
257
258
/** Whether the context Tapscript, ensuring the only other possibility is P2WSH. */
259
constexpr bool IsTapscript(MiniscriptContext ms_ctx)
260
10.4M
{
261
10.4M
    switch (ms_ctx) {
262
65.9k
        case MiniscriptContext::P2WSH: return false;
263
10.3M
        case MiniscriptContext::TAPSCRIPT: return true;
264
10.4M
    }
265
10.4M
    assert(false);
266
0
}
267
268
namespace internal {
269
270
//! The maximum size of a witness item for a Miniscript under Tapscript context. (A BIP340 signature with a sighash type byte.)
271
inline constexpr uint32_t MAX_TAPMINISCRIPT_STACK_ELEM_SIZE{65};
272
273
//! version + nLockTime
274
inline constexpr uint32_t TX_OVERHEAD{4 + 4};
275
//! prevout + nSequence + scriptSig
276
inline constexpr uint32_t TXIN_BYTES_NO_WITNESS{36 + 4 + 1};
277
//! nValue + script len + OP_0 + pushdata 32.
278
inline constexpr uint32_t P2WSH_TXOUT_BYTES{8 + 1 + 1 + 33};
279
//! Data other than the witness in a transaction. Overhead + vin count + one vin + vout count + one vout + segwit marker
280
inline constexpr uint32_t TX_BODY_LEEWAY_WEIGHT{(TX_OVERHEAD + GetSizeOfCompactSize(1) + TXIN_BYTES_NO_WITNESS + GetSizeOfCompactSize(1) + P2WSH_TXOUT_BYTES) * WITNESS_SCALE_FACTOR + 2};
281
//! Maximum possible stack size to spend a Taproot output (excluding the script itself).
282
inline constexpr uint32_t MAX_TAPSCRIPT_SAT_SIZE{GetSizeOfCompactSize(MAX_STACK_SIZE) + (GetSizeOfCompactSize(MAX_TAPMINISCRIPT_STACK_ELEM_SIZE) + MAX_TAPMINISCRIPT_STACK_ELEM_SIZE) * MAX_STACK_SIZE + GetSizeOfCompactSize(TAPROOT_CONTROL_MAX_SIZE) + TAPROOT_CONTROL_MAX_SIZE};
283
/** The maximum size of a script depending on the context. */
284
constexpr uint32_t MaxScriptSize(MiniscriptContext ms_ctx)
285
2.70M
{
286
2.70M
    if (IsTapscript(ms_ctx)) {
287
        // Leaf scripts under Tapscript are not explicitly limited in size. They are only implicitly
288
        // bounded by the maximum standard size of a spending transaction. Let the maximum script
289
        // size conservatively be small enough such that even a maximum sized witness and a reasonably
290
        // sized spending transaction can spend an output paying to this script without running into
291
        // the maximum standard tx size limit.
292
2.68M
        constexpr auto max_size{MAX_STANDARD_TX_WEIGHT - TX_BODY_LEEWAY_WEIGHT - MAX_TAPSCRIPT_SAT_SIZE};
293
2.68M
        return max_size - GetSizeOfCompactSize(max_size);
294
2.68M
    }
295
23.6k
    return MAX_STANDARD_P2WSH_SCRIPT_SIZE;
296
2.70M
}
297
298
//! Helper function for Node::CalcType.
299
Type ComputeType(Fragment fragment, Type x, Type y, Type z, const std::vector<Type>& sub_types, uint32_t k, size_t data_size, size_t n_subs, size_t n_keys, MiniscriptContext ms_ctx);
300
301
//! Helper function for Node::CalcScriptLen.
302
size_t ComputeScriptLen(Fragment fragment, Type sub0typ, size_t subsize, uint32_t k, size_t n_subs, size_t n_keys, MiniscriptContext ms_ctx);
303
304
//! A helper sanitizer/checker for the output of CalcType.
305
Type SanitizeType(Type x);
306
307
//! An object representing a sequence of witness stack elements.
308
struct InputStack {
309
    /** Whether this stack is valid for its intended purpose (satisfaction or dissatisfaction of a Node).
310
     *  The MAYBE value is used for size estimation, when keys/preimages may actually be unavailable,
311
     *  but may be available at signing time. This makes the InputStack structure and signing logic,
312
     *  filled with dummy signatures/preimages usable for witness size estimation.
313
     */
314
    Availability available = Availability::YES;
315
    //! Whether this stack contains a digital signature.
316
    bool has_sig = false;
317
    //! Whether this stack is malleable (can be turned into an equally valid other stack by a third party).
318
    bool malleable = false;
319
    //! Whether this stack is non-canonical (using a construction known to be unnecessary for satisfaction).
320
    //! Note that this flag does not affect the satisfaction algorithm; it is only used for sanity checking.
321
    bool non_canon = false;
322
    //! Serialized witness size.
323
    size_t size = 0;
324
    //! Data elements.
325
    std::vector<std::vector<unsigned char>> stack;
326
    //! Construct an empty stack (valid).
327
1.37k
    InputStack() = default;
328
    //! Construct a valid single-element stack (with an element up to 75 bytes).
329
480k
    InputStack(std::vector<unsigned char> in) : size(in.size() + 1), stack(Vector(std::move(in))) {}
330
    //! Change availability
331
    InputStack& SetAvailable(Availability avail);
332
    //! Mark this input stack as having a signature.
333
    InputStack& SetWithSig();
334
    //! Mark this input stack as non-canonical (known to not be necessary in non-malleable satisfactions).
335
    InputStack& SetNonCanon();
336
    //! Mark this input stack as malleable.
337
    InputStack& SetMalleable(bool x = true);
338
    //! Concatenate two input stacks.
339
    friend InputStack operator+(InputStack a, InputStack b);
340
    //! Choose between two potential input stacks.
341
    friend InputStack operator|(InputStack a, InputStack b);
342
};
343
344
/** A stack consisting of a single zero-length element (interpreted as 0 by the script interpreter in numeric context). */
345
inline const auto ZERO = InputStack(std::vector<unsigned char>());
346
/** A stack consisting of a single malleable 32-byte 0x0000...0000 element (for dissatisfying hash challenges). */
347
inline const auto ZERO32 = InputStack(std::vector<unsigned char>(32, 0)).SetMalleable();
348
/** A stack consisting of a single 0x01 element (interpreted as 1 by the script interpreted in numeric context). */
349
inline const auto ONE = InputStack(Vector((unsigned char)1));
350
/** The empty stack. */
351
inline const auto EMPTY = InputStack();
352
/** A stack representing the lack of any (dis)satisfactions. */
353
inline const auto INVALID = InputStack().SetAvailable(Availability::NO);
354
355
//! A pair of a satisfaction and a dissatisfaction InputStack.
356
struct InputResult {
357
    InputStack nsat, sat;
358
359
    template<typename A, typename B>
360
841k
    InputResult(A&& in_nsat, B&& in_sat) : nsat(std::forward<A>(in_nsat)), sat(std::forward<B>(in_sat)) {}
miniscript::internal::InputResult::InputResult<miniscript::internal::InputStack const&, miniscript::internal::InputStack&>(miniscript::internal::InputStack const&, miniscript::internal::InputStack&)
Line
Count
Source
360
379k
    InputResult(A&& in_nsat, B&& in_sat) : nsat(std::forward<A>(in_nsat)), sat(std::forward<B>(in_sat)) {}
miniscript::internal::InputResult::InputResult<miniscript::internal::InputStack, miniscript::internal::InputStack&>(miniscript::internal::InputStack&&, miniscript::internal::InputStack&)
Line
Count
Source
360
1.11k
    InputResult(A&& in_nsat, B&& in_sat) : nsat(std::forward<A>(in_nsat)), sat(std::forward<B>(in_sat)) {}
miniscript::internal::InputResult::InputResult<miniscript::internal::InputStack, miniscript::internal::InputStack>(miniscript::internal::InputStack&&, miniscript::internal::InputStack&&)
Line
Count
Source
360
412k
    InputResult(A&& in_nsat, B&& in_sat) : nsat(std::forward<A>(in_nsat)), sat(std::forward<B>(in_sat)) {}
miniscript::internal::InputResult::InputResult<miniscript::internal::InputStack const&, miniscript::internal::InputStack const&>(miniscript::internal::InputStack const&, miniscript::internal::InputStack const&)
Line
Count
Source
360
42.0k
    InputResult(A&& in_nsat, B&& in_sat) : nsat(std::forward<A>(in_nsat)), sat(std::forward<B>(in_sat)) {}
miniscript::internal::InputResult::InputResult<miniscript::internal::InputStack&, miniscript::internal::InputStack>(miniscript::internal::InputStack&, miniscript::internal::InputStack&&)
Line
Count
Source
360
2.50k
    InputResult(A&& in_nsat, B&& in_sat) : nsat(std::forward<A>(in_nsat)), sat(std::forward<B>(in_sat)) {}
miniscript::internal::InputResult::InputResult<miniscript::internal::InputStack const&, miniscript::internal::InputStack>(miniscript::internal::InputStack const&, miniscript::internal::InputStack&&)
Line
Count
Source
360
2.85k
    InputResult(A&& in_nsat, B&& in_sat) : nsat(std::forward<A>(in_nsat)), sat(std::forward<B>(in_sat)) {}
361
};
362
363
//! Class whose objects represent the maximum of a list of integers.
364
template <typename I>
365
class MaxInt
366
{
367
    bool valid;
368
    I value;
369
370
public:
371
44.0k
    MaxInt() : valid(false), value(0) {}
372
111k
    MaxInt(I val) : valid(true), value(val) {}
373
374
2.70k
    bool Valid() const { return valid; }
375
2.69k
    I Value() const { return value; }
376
377
57.9k
    friend MaxInt<I> operator+(const MaxInt<I>& a, const MaxInt<I>& b) {
378
57.9k
        if (!a.valid || !b.valid) return {};
379
43.3k
        return a.value + b.value;
380
57.9k
    }
381
382
9.86k
    friend MaxInt<I> operator|(const MaxInt<I>& a, const MaxInt<I>& b) {
383
9.86k
        if (!a.valid) return b;
384
8.62k
        if (!b.valid) return a;
385
7.29k
        return std::max(a.value, b.value);
386
8.62k
    }
387
};
388
389
struct Ops {
390
    //! Non-push opcodes.
391
    uint32_t count;
392
    //! Number of keys in possibly executed OP_CHECKMULTISIG(VERIFY)s to satisfy.
393
    MaxInt<uint32_t> sat;
394
    //! Number of keys in possibly executed OP_CHECKMULTISIG(VERIFY)s to dissatisfy.
395
    MaxInt<uint32_t> dsat;
396
397
3.74M
    Ops(uint32_t in_count, MaxInt<uint32_t> in_sat, MaxInt<uint32_t> in_dsat) : count(in_count), sat(in_sat), dsat(in_dsat) {};
398
};
399
400
/** A data structure to help the calculation of stack size limits.
401
 *
402
 * Conceptually, every SatInfo object corresponds to a (possibly empty) set of script execution
403
 * traces (sequences of opcodes).
404
 * - SatInfo{} corresponds to the empty set.
405
 * - SatInfo{n, e} corresponds to a single trace whose net effect is removing n elements from the
406
 *   stack (may be negative for a net increase), and reaches a maximum of e stack elements more
407
 *   than it ends with.
408
 * - operator| is the union operation: (a | b) corresponds to the union of the traces in a and the
409
 *   traces in b.
410
 * - operator+ is the concatenation operator: (a + b) corresponds to the set of traces formed by
411
 *   concatenating any trace in a with any trace in b.
412
 *
413
 * Its fields are:
414
 * - valid is true if the set is non-empty.
415
 * - netdiff (if valid) is the largest difference between stack size at the beginning and at the
416
 *   end of the script across all traces in the set.
417
 * - exec (if valid) is the largest difference between stack size anywhere during execution and at
418
 *   the end of the script, across all traces in the set (note that this is not necessarily due
419
 *   to the same trace as the one that resulted in the value for netdiff).
420
 *
421
 * This allows us to build up stack size limits for any script efficiently, by starting from the
422
 * individual opcodes miniscripts correspond to, using concatenation to construct scripts, and
423
 * using the union operation to choose between execution branches. Since any top-level script
424
 * satisfaction ends with a single stack element, we know that for a full script:
425
 * - netdiff+1 is the maximal initial stack size (relevant for P2WSH stack limits).
426
 * - exec+1 is the maximal stack size reached during execution (relevant for P2TR stack limits).
427
 *
428
 * Mathematically, SatInfo forms a semiring:
429
 * - operator| is the semiring addition operator, with identity SatInfo{}, and which is commutative
430
 *   and associative.
431
 * - operator+ is the semiring multiplication operator, with identity SatInfo{0}, and which is
432
 *   associative.
433
 * - operator+ is distributive over operator|, so (a + (b | c)) = (a+b | a+c). This means we do not
434
 *   need to actually materialize all possible full execution traces over the whole script (which
435
 *   may be exponential in the length of the script); instead we can use the union operation at the
436
 *   individual subexpression level, and concatenate the result with subexpressions before and
437
 *   after it.
438
 * - It is not a commutative semiring, because a+b can differ from b+a. For example, "OP_1 OP_DROP"
439
 *   has exec=1, while "OP_DROP OP_1" has exec=0.
440
 */
441
class SatInfo
442
{
443
    //! Whether a canonical satisfaction/dissatisfaction is possible at all.
444
    bool valid;
445
    //! How much higher the stack size at start of execution can be compared to at the end.
446
    int32_t netdiff;
447
    //! How much higher the stack size can be during execution compared to at the end.
448
    int32_t exec;
449
450
public:
451
    /** Empty script set. */
452
27.4k
    constexpr SatInfo() noexcept : valid(false), netdiff(0), exec(0) {}
453
454
    /** Script set with a single script in it, with specified netdiff and exec. */
455
    constexpr SatInfo(int32_t in_netdiff, int32_t in_exec) noexcept :
456
146k
        valid{true}, netdiff{in_netdiff}, exec{in_exec} {}
457
458
7.19k
    bool Valid() const { return valid; }
459
2.73k
    int32_t NetDiff() const { return netdiff; }
460
4.43k
    int32_t Exec() const { return exec; }
461
462
    /** Script set union. */
463
    constexpr friend SatInfo operator|(const SatInfo& a, const SatInfo& b) noexcept
464
4.93k
    {
465
        // Union with an empty set is itself.
466
4.93k
        if (!a.valid) return b;
467
4.31k
        if (!b.valid) return a;
468
        // Otherwise the netdiff and exec of the union is the maximum of the individual values.
469
3.64k
        return {std::max(a.netdiff, b.netdiff), std::max(a.exec, b.exec)};
470
4.31k
    }
471
472
    /** Script set concatenation. */
473
    constexpr friend SatInfo operator+(const SatInfo& a, const SatInfo& b) noexcept
474
83.7k
    {
475
        // Concatenation with an empty set yields an empty set.
476
83.7k
        if (!a.valid || !b.valid) return {};
477
        // Otherwise, the maximum stack size difference for the combined scripts is the sum of the
478
        // netdiffs, and the maximum stack size difference anywhere is either b.exec (if the
479
        // maximum occurred in b) or b.netdiff+a.exec (if the maximum occurred in a).
480
71.0k
        return {a.netdiff + b.netdiff, std::max(b.exec, b.netdiff + a.exec)};
481
83.7k
    }
482
483
    /** The empty script. */
484
822
    static constexpr SatInfo Empty() noexcept { return {0, 0}; }
485
    /** A script consisting of a single push opcode. */
486
19.4k
    static constexpr SatInfo Push() noexcept { return {-1, 0}; }
487
    /** A script consisting of a single hash opcode. */
488
1.32k
    static constexpr SatInfo Hash() noexcept { return {0, 0}; }
489
    /** A script consisting of just a repurposed nop (OP_CHECKLOCKTIMEVERIFY, OP_CHECKSEQUENCEVERIFY). */
490
9.45k
    static constexpr SatInfo Nop() noexcept { return {0, 0}; }
491
    /** A script consisting of just OP_IF or OP_NOTIF. Note that OP_ELSE and OP_ENDIF have no stack effect. */
492
2.78k
    static constexpr SatInfo If() noexcept { return {1, 1}; }
493
    /** A script consisting of just a binary operator (OP_BOOLAND, OP_BOOLOR, OP_ADD). */
494
15.8k
    static constexpr SatInfo BinaryOp() noexcept { return {1, 1}; }
495
496
    // Scripts for specific individual opcodes.
497
1.16k
    static constexpr SatInfo OP_DUP() noexcept { return {-1, 0}; }
498
381
    static constexpr SatInfo OP_IFDUP(bool nonzero) noexcept { return {nonzero ? -1 : 0, 0}; }
499
1.32k
    static constexpr SatInfo OP_EQUALVERIFY() noexcept { return {2, 2}; }
500
1.21k
    static constexpr SatInfo OP_EQUAL() noexcept { return {1, 1}; }
501
424
    static constexpr SatInfo OP_SIZE() noexcept { return {-1, 0}; }
502
14.7k
    static constexpr SatInfo OP_CHECKSIG() noexcept { return {1, 1}; }
503
32
    static constexpr SatInfo OP_0NOTEQUAL() noexcept { return {0, 0}; }
504
1.99k
    static constexpr SatInfo OP_VERIFY() noexcept { return {1, 1}; }
505
};
506
507
class StackSize
508
{
509
    SatInfo sat, dsat;
510
511
public:
512
30.9k
    constexpr StackSize(SatInfo in_sat, SatInfo in_dsat) noexcept : sat(in_sat), dsat(in_dsat) {};
513
8.44k
    constexpr StackSize(SatInfo in_both) noexcept : sat(in_both), dsat(in_both) {};
514
515
49.2k
    const SatInfo& Sat() const { return sat; }
516
29.3k
    const SatInfo& Dsat() const { return dsat; }
517
};
518
519
struct WitnessSize {
520
    //! Maximum witness size to satisfy;
521
    MaxInt<uint32_t> sat;
522
    //! Maximum witness size to dissatisfy;
523
    MaxInt<uint32_t> dsat;
524
525
32.0k
    WitnessSize(MaxInt<uint32_t> in_sat, MaxInt<uint32_t> in_dsat) : sat(in_sat), dsat(in_dsat) {};
526
};
527
528
struct NoDupCheck {};
529
530
} // namespace internal
531
532
//! A node in a miniscript expression.
533
template <typename Key>
534
class Node
535
{
536
    //! What node type this node is.
537
    enum Fragment fragment;
538
    //! The k parameter (time for OLDER/AFTER, threshold for THRESH(_M))
539
    uint32_t k = 0;
540
    //! The keys used by this expression (only for PK_K/PK_H/MULTI)
541
    std::vector<Key> keys;
542
    //! The data bytes in this expression (only for HASH160/HASH256/SHA256/RIPEMD160).
543
    std::vector<unsigned char> data;
544
    //! Subexpressions (for WRAP_*/AND_*/OR_*/ANDOR/THRESH)
545
    std::vector<Node> subs;
546
    //! The Script context for this node. Either P2WSH or Tapscript.
547
    MiniscriptContext m_script_ctx;
548
549
public:
550
    // Permit 1 level deep recursion since we own instances of our own type.
551
    // NOLINTBEGIN(misc-no-recursion)
552
    ~Node()
553
8.58M
    {
554
        // Destroy the subexpressions iteratively after moving out their
555
        // subexpressions to avoid a stack-overflow due to recursive calls to
556
        // the subs' destructors.
557
        // We move vectors in order to only update array-pointers inside them
558
        // rather than moving individual Node instances which would involve
559
        // moving/copying each Node field.
560
8.58M
        std::vector<std::vector<Node>> queue;
561
8.58M
        queue.push_back(std::move(subs));
562
12.3M
        do {
563
12.3M
            auto flattening{std::move(queue.back())};
564
12.3M
            queue.pop_back();
565
12.3M
            for (Node& n : flattening) {
566
3.73M
                if (!n.subs.empty()) queue.push_back(std::move(n.subs));
567
3.73M
            }
568
12.3M
        } while (!queue.empty());
569
8.58M
    }
miniscript::Node<CPubKey>::~Node()
Line
Count
Source
553
73.4k
    {
554
        // Destroy the subexpressions iteratively after moving out their
555
        // subexpressions to avoid a stack-overflow due to recursive calls to
556
        // the subs' destructors.
557
        // We move vectors in order to only update array-pointers inside them
558
        // rather than moving individual Node instances which would involve
559
        // moving/copying each Node field.
560
73.4k
        std::vector<std::vector<Node>> queue;
561
73.4k
        queue.push_back(std::move(subs));
562
90.4k
        do {
563
90.4k
            auto flattening{std::move(queue.back())};
564
90.4k
            queue.pop_back();
565
90.4k
            for (Node& n : flattening) {
566
26.1k
                if (!n.subs.empty()) queue.push_back(std::move(n.subs));
567
26.1k
            }
568
90.4k
        } while (!queue.empty());
569
73.4k
    }
miniscript::Node<unsigned int>::~Node()
Line
Count
Source
553
4.52M
    {
554
        // Destroy the subexpressions iteratively after moving out their
555
        // subexpressions to avoid a stack-overflow due to recursive calls to
556
        // the subs' destructors.
557
        // We move vectors in order to only update array-pointers inside them
558
        // rather than moving individual Node instances which would involve
559
        // moving/copying each Node field.
560
4.52M
        std::vector<std::vector<Node>> queue;
561
4.52M
        queue.push_back(std::move(subs));
562
6.24M
        do {
563
6.24M
            auto flattening{std::move(queue.back())};
564
6.24M
            queue.pop_back();
565
6.24M
            for (Node& n : flattening) {
566
1.72M
                if (!n.subs.empty()) queue.push_back(std::move(n.subs));
567
1.72M
            }
568
6.24M
        } while (!queue.empty());
569
4.52M
    }
miniscript::Node<XOnlyPubKey>::~Node()
Line
Count
Source
553
3.98M
    {
554
        // Destroy the subexpressions iteratively after moving out their
555
        // subexpressions to avoid a stack-overflow due to recursive calls to
556
        // the subs' destructors.
557
        // We move vectors in order to only update array-pointers inside them
558
        // rather than moving individual Node instances which would involve
559
        // moving/copying each Node field.
560
3.98M
        std::vector<std::vector<Node>> queue;
561
3.98M
        queue.push_back(std::move(subs));
562
5.96M
        do {
563
5.96M
            auto flattening{std::move(queue.back())};
564
5.96M
            queue.pop_back();
565
5.96M
            for (Node& n : flattening) {
566
1.98M
                if (!n.subs.empty()) queue.push_back(std::move(n.subs));
567
1.98M
            }
568
5.96M
        } while (!queue.empty());
569
3.98M
    }
570
    // NOLINTEND(misc-no-recursion)
571
572
    Node<Key> Clone() const
573
193
    {
574
        // Use TreeEval() to avoid a stack-overflow due to recursion
575
531k
        auto upfn = [](const Node& node, std::span<Node> children) {
576
531k
            std::vector<Node> new_subs;
577
531k
            for (auto& child : children) {
578
                // It's fine to move from children as they are new nodes having
579
                // been produced by calling this function one level down.
580
530k
                new_subs.push_back(std::move(child));
581
530k
            }
582
531k
            return Node{internal::NoDupCheck{}, node.m_script_ctx, node.fragment, std::move(new_subs), node.keys, node.data, node.k};
583
531k
        };
584
193
        return TreeEval<Node>(upfn);
585
193
    }
586
587
1.00M
    enum Fragment Fragment() const { return fragment; }
miniscript::Node<CPubKey>::Fragment() const
Line
Count
Source
587
8.47k
    enum Fragment Fragment() const { return fragment; }
miniscript::Node<unsigned int>::Fragment() const
Line
Count
Source
587
995k
    enum Fragment Fragment() const { return fragment; }
588
2.35k
    uint32_t K() const { return k; }
miniscript::Node<CPubKey>::K() const
Line
Count
Source
588
2.10k
    uint32_t K() const { return k; }
miniscript::Node<unsigned int>::K() const
Line
Count
Source
588
249
    uint32_t K() const { return k; }
589
8.47k
    const std::vector<Key>& Keys() const { return keys; }
590
48
    const std::vector<unsigned char>& Data() const { return data; }
591
2.20M
    const std::vector<Node>& Subs() const { return subs; }
miniscript::Node<CPubKey>::Subs() const
Line
Count
Source
591
8.47k
    const std::vector<Node>& Subs() const { return subs; }
miniscript::Node<unsigned int>::Subs() const
Line
Count
Source
591
2.19M
    const std::vector<Node>& Subs() const { return subs; }
592
593
private:
594
    //! Cached ops counts.
595
    internal::Ops ops;
596
    //! Cached stack size bounds.
597
    internal::StackSize ss;
598
    //! Cached witness size bounds.
599
    internal::WitnessSize ws;
600
    //! Cached expression type (computed by CalcType and fed through SanitizeType).
601
    Type typ;
602
    //! Cached script length (computed by CalcScriptLen).
603
    size_t scriptlen;
604
    //! Whether a public key appears more than once in this node. This value is initialized
605
    //! by all constructors except the NoDupCheck ones. The NoDupCheck ones skip the
606
    //! computation, requiring it to be done manually by invoking DuplicateKeyCheck().
607
    //! DuplicateKeyCheck(), or a non-NoDupCheck constructor, will compute has_duplicate_keys
608
    //! for all subnodes as well.
609
    mutable std::optional<bool> has_duplicate_keys;
610
611
    // Constructor which takes all of the data that a Node could possibly contain.
612
    // This is kept private as no valid fragment has all of these arguments.
613
    // Only used by Clone()
614
    Node(internal::NoDupCheck, MiniscriptContext script_ctx, enum Fragment nt, std::vector<Node> sub, std::vector<Key> key, std::vector<unsigned char> arg, uint32_t val)
615
531k
        : fragment(nt), k(val), keys(std::move(key)), data(std::move(arg)), subs(std::move(sub)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
616
617
    //! Compute the length of the script for this miniscript (including children).
618
    size_t CalcScriptLen() const
619
3.74M
    {
620
3.74M
        size_t subsize = 0;
621
3.74M
        for (const auto& sub : subs) {
622
3.73M
            subsize += sub.ScriptSize();
623
3.73M
        }
624
3.74M
        Type sub0type = subs.size() > 0 ? subs[0].GetType() : ""_mst;
625
3.74M
        return internal::ComputeScriptLen(fragment, sub0type, subsize, k, subs.size(), keys.size(), m_script_ctx);
626
3.74M
    }
miniscript::Node<CPubKey>::CalcScriptLen() const
Line
Count
Source
619
28.4k
    {
620
28.4k
        size_t subsize = 0;
621
28.4k
        for (const auto& sub : subs) {
622
26.1k
            subsize += sub.ScriptSize();
623
26.1k
        }
624
28.4k
        Type sub0type = subs.size() > 0 ? subs[0].GetType() : ""_mst;
625
28.4k
        return internal::ComputeScriptLen(fragment, sub0type, subsize, k, subs.size(), keys.size(), m_script_ctx);
626
28.4k
    }
miniscript::Node<unsigned int>::CalcScriptLen() const
Line
Count
Source
619
1.72M
    {
620
1.72M
        size_t subsize = 0;
621
1.72M
        for (const auto& sub : subs) {
622
1.72M
            subsize += sub.ScriptSize();
623
1.72M
        }
624
1.72M
        Type sub0type = subs.size() > 0 ? subs[0].GetType() : ""_mst;
625
1.72M
        return internal::ComputeScriptLen(fragment, sub0type, subsize, k, subs.size(), keys.size(), m_script_ctx);
626
1.72M
    }
miniscript::Node<XOnlyPubKey>::CalcScriptLen() const
Line
Count
Source
619
1.98M
    {
620
1.98M
        size_t subsize = 0;
621
1.98M
        for (const auto& sub : subs) {
622
1.98M
            subsize += sub.ScriptSize();
623
1.98M
        }
624
1.98M
        Type sub0type = subs.size() > 0 ? subs[0].GetType() : ""_mst;
625
1.98M
        return internal::ComputeScriptLen(fragment, sub0type, subsize, k, subs.size(), keys.size(), m_script_ctx);
626
1.98M
    }
627
628
    /* Apply a recursive algorithm to a Miniscript tree, without actual recursive calls.
629
     *
630
     * The algorithm is defined by two functions: downfn and upfn. Conceptually, the
631
     * result can be thought of as first using downfn to compute a "state" for each node,
632
     * from the root down to the leaves. Then upfn is used to compute a "result" for each
633
     * node, from the leaves back up to the root, which is then returned. In the actual
634
     * implementation, both functions are invoked in an interleaved fashion, performing a
635
     * depth-first traversal of the tree.
636
     *
637
     * In more detail, it is invoked as node.TreeEvalMaybe<Result>(root, downfn, upfn):
638
     * - root is the state of the root node, of type State.
639
     * - downfn is a callable (State&, const Node&, size_t) -> State, which given a
640
     *   node, its state, and an index of one of its children, computes the state of that
641
     *   child. It can modify the state. Children of a given node will have downfn()
642
     *   called in order.
643
     * - upfn is a callable (State&&, const Node&, std::span<Result>) -> std::optional<Result>,
644
     *   which given a node, its state, and a span of the results of its children,
645
     *   computes the result of the node. If std::nullopt is returned by upfn,
646
     *   TreeEvalMaybe() immediately returns std::nullopt.
647
     * The return value of TreeEvalMaybe is the result of the root node.
648
     *
649
     * Result type cannot be bool due to the std::vector<bool> specialization.
650
     */
651
    template<typename Result, typename State, typename DownFn, typename UpFn>
652
    std::optional<Result> TreeEvalMaybe(State root_state, DownFn downfn, UpFn upfn) const
653
18.5k
    {
654
        /** Entries of the explicit stack tracked in this algorithm. */
655
18.5k
        struct StackElem
656
18.5k
        {
657
18.5k
            const Node& node; //!< The node being evaluated.
658
18.5k
            size_t expanded; //!< How many children of this node have been expanded.
659
18.5k
            State state; //!< The state for that node.
660
661
18.5k
            StackElem(const Node& node_, size_t exp_, State&& state_) :
662
11.8M
                node(node_), expanded(exp_), state(std::move(state_)) {}
miniscript_tests.cpp:std::optional<(anonymous namespace)::KeyConverter> miniscript::Node<CPubKey>::TreeEvalMaybe<CScript, bool, CScript miniscript::Node<CPubKey>::ToScript<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, unsigned long), (anonymous namespace)::KeyConverter miniscript::Node<CPubKey>::TreeEval<CScript, bool, CScript miniscript::Node<CPubKey>::ToScript<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, unsigned long)&, CScript miniscript::Node<CPubKey>::ToScript<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, std::span<CScript, 18446744073709551615ul>)>(bool, CScript miniscript::Node<CPubKey>::ToScript<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, unsigned long)&, CScript miniscript::Node<CPubKey>::ToScript<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, std::span<CScript, 18446744073709551615ul>)) const::'lambda'(bool&&, miniscript::Node<CPubKey> const&, std::span<CScript, 18446744073709551615ul>)>(bool, CScript miniscript::Node<CPubKey>::ToScript<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, unsigned long)&, CScript miniscript::Node<CPubKey>::ToScript<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, std::span<CScript, 18446744073709551615ul>)) const::StackElem::StackElem(miniscript::Node<CPubKey> const&, unsigned long, bool&&)
Line
Count
Source
662
25.4k
                node(node_), expanded(exp_), state(std::move(state_)) {}
miniscript_tests.cpp:std::optional<(anonymous namespace)::Satisfier> miniscript::Node<CPubKey>::TreeEvalMaybe<miniscript::internal::InputResult, (anonymous namespace)::Satisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, (anonymous namespace)::Satisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::Satisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long), (anonymous namespace)::Satisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::Satisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>), (anonymous namespace)::Satisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::Satisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long), (anonymous namespace)::Satisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::Satisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::StackElem::StackElem(miniscript::Node<CPubKey> const&, unsigned long, (anonymous namespace)::Satisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState&&)
Line
Count
Source
662
1.61M
                node(node_), expanded(exp_), state(std::move(state_)) {}
miniscript_tests.cpp:std::optional<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)> miniscript::Node<CPubKey>::TreeEvalMaybe<int, (anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&) miniscript::Node<CPubKey>::TreeEval<int, bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)>(bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)) const::DummyState, (anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&) miniscript::Node<CPubKey>::TreeEval<int, bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)>(bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&) miniscript::Node<CPubKey>::TreeEval<int, bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)>(bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long), (anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&) miniscript::Node<CPubKey>::TreeEval<int, bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)>(bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&) miniscript::Node<CPubKey>::TreeEval<int, bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)>(bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)>(bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>), (anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&) miniscript::Node<CPubKey>::TreeEval<int, bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)>(bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&) miniscript::Node<CPubKey>::TreeEval<int, bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)>(bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long), (anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&) miniscript::Node<CPubKey>::TreeEval<int, bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)>(bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&) miniscript::Node<CPubKey>::TreeEval<int, bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)>(bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)) const::StackElem::StackElem(miniscript::Node<CPubKey> const&, unsigned long, (anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&) miniscript::Node<CPubKey>::TreeEval<int, bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)>(bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)) const::DummyState&&)
Line
Count
Source
662
25.4k
                node(node_), expanded(exp_), state(std::move(state_)) {}
miniscript_tests.cpp:std::optional<(anonymous namespace)::KeyConverter> miniscript::Node<CPubKey>::TreeEvalMaybe<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, (anonymous namespace)::KeyConverter miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::DummyState, (anonymous namespace)::KeyConverter miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::KeyConverter miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long), (anonymous namespace)::KeyConverter miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::KeyConverter miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>), (anonymous namespace)::KeyConverter miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::KeyConverter miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long), (anonymous namespace)::KeyConverter miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::KeyConverter miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::StackElem::StackElem(miniscript::Node<CPubKey> const&, unsigned long, (anonymous namespace)::KeyConverter miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::DummyState&&)
Line
Count
Source
662
23.2k
                node(node_), expanded(exp_), state(std::move(state_)) {}
std::optional<miniscript::Node<CPubKey> const*> miniscript::Node<CPubKey>::TreeEvalMaybe<miniscript::Node<CPubKey> const*, miniscript::Node<CPubKey> const* miniscript::Node<CPubKey>::TreeEval<miniscript::Node<CPubKey> const*, miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)>(miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const* miniscript::Node<CPubKey>::TreeEval<miniscript::Node<CPubKey> const*, miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)>(miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)) const::'lambda'(miniscript::Node<CPubKey> const* miniscript::Node<CPubKey>::TreeEval<miniscript::Node<CPubKey> const*, miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)>(miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long), miniscript::Node<CPubKey> const* miniscript::Node<CPubKey>::TreeEval<miniscript::Node<CPubKey> const*, miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)>(miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)) const::'lambda'(miniscript::Node<CPubKey> const* miniscript::Node<CPubKey>::TreeEval<miniscript::Node<CPubKey> const*, miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)>(miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)>(miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>), miniscript::Node<CPubKey> const* miniscript::Node<CPubKey>::TreeEval<miniscript::Node<CPubKey> const*, miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)>(miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)) const::'lambda'(miniscript::Node<CPubKey> const* miniscript::Node<CPubKey>::TreeEval<miniscript::Node<CPubKey> const*, miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)>(miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long), miniscript::Node<CPubKey> const* miniscript::Node<CPubKey>::TreeEval<miniscript::Node<CPubKey> const*, miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)>(miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)) const::'lambda'(miniscript::Node<CPubKey> const* miniscript::Node<CPubKey>::TreeEval<miniscript::Node<CPubKey> const*, miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)>(miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)) const::StackElem::StackElem(miniscript::Node<CPubKey> const&, unsigned long, miniscript::Node<CPubKey> const* miniscript::Node<CPubKey>::TreeEval<miniscript::Node<CPubKey> const*, miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)>(miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)) const::DummyState&&)
Line
Count
Source
662
7
                node(node_), expanded(exp_), state(std::move(state_)) {}
miniscript_tests.cpp:std::optional<(anonymous namespace)::KeyConverter> miniscript::Node<CPubKey>::TreeEvalMaybe<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, bool, std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<CPubKey>::ToString<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&, bool&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, unsigned long), std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<CPubKey>::ToString<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&, bool&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, std::span<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, 18446744073709551615ul>)>(bool, std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<CPubKey>::ToString<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&, bool&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, unsigned long), std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<CPubKey>::ToString<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&, bool&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, std::span<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, 18446744073709551615ul>)) const::StackElem::StackElem(miniscript::Node<CPubKey> const&, unsigned long, bool&&)
Line
Count
Source
662
4
                node(node_), expanded(exp_), state(std::move(state_)) {}
std::optional<miniscript::Node<unsigned int>> miniscript::Node<unsigned int>::TreeEvalMaybe<miniscript::Node<unsigned int>, miniscript::Node<unsigned int> miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int>, miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int>, miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)) const::'lambda'(miniscript::Node<unsigned int> miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int>, miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, unsigned long), miniscript::Node<unsigned int> miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int>, miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)) const::'lambda'(miniscript::Node<unsigned int> miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int>, miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>), miniscript::Node<unsigned int> miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int>, miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)) const::'lambda'(miniscript::Node<unsigned int> miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int>, miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, unsigned long), miniscript::Node<unsigned int> miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int>, miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)) const::'lambda'(miniscript::Node<unsigned int> miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int>, miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)) const::StackElem::StackElem(miniscript::Node<unsigned int> const&, unsigned long, miniscript::Node<unsigned int> miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int>, miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)) const::DummyState&&)
Line
Count
Source
662
531k
                node(node_), expanded(exp_), state(std::move(state_)) {}
descriptor.cpp:std::optional<(anonymous namespace)::KeyParser> miniscript::Node<unsigned int>::TreeEvalMaybe<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, (anonymous namespace)::KeyParser miniscript::Node<unsigned int>::TreeEval<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)>(void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)) const::DummyState, (anonymous namespace)::KeyParser miniscript::Node<unsigned int>::TreeEval<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)>(void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::KeyParser miniscript::Node<unsigned int>::TreeEval<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)>(void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, unsigned long), (anonymous namespace)::KeyParser miniscript::Node<unsigned int>::TreeEval<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)>(void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::KeyParser miniscript::Node<unsigned int>::TreeEval<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)>(void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)>(void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>), (anonymous namespace)::KeyParser miniscript::Node<unsigned int>::TreeEval<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)>(void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::KeyParser miniscript::Node<unsigned int>::TreeEval<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)>(void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, unsigned long), (anonymous namespace)::KeyParser miniscript::Node<unsigned int>::TreeEval<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)>(void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::KeyParser miniscript::Node<unsigned int>::TreeEval<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)>(void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)) const::StackElem::StackElem(miniscript::Node<unsigned int> const&, unsigned long, (anonymous namespace)::KeyParser miniscript::Node<unsigned int>::TreeEval<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)>(void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)) const::DummyState&&)
Line
Count
Source
662
995k
                node(node_), expanded(exp_), state(std::move(state_)) {}
std::optional<miniscript::Node<unsigned int> const*> miniscript::Node<unsigned int>::TreeEvalMaybe<miniscript::Node<unsigned int> const*, miniscript::Node<unsigned int> const* miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int> const*, miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const* miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int> const*, miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)) const::'lambda'(miniscript::Node<unsigned int> const* miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int> const*, miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, unsigned long), miniscript::Node<unsigned int> const* miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int> const*, miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)) const::'lambda'(miniscript::Node<unsigned int> const* miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int> const*, miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>), miniscript::Node<unsigned int> const* miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int> const*, miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)) const::'lambda'(miniscript::Node<unsigned int> const* miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int> const*, miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, unsigned long), miniscript::Node<unsigned int> const* miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int> const*, miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)) const::'lambda'(miniscript::Node<unsigned int> const* miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int> const*, miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)) const::StackElem::StackElem(miniscript::Node<unsigned int> const&, unsigned long, miniscript::Node<unsigned int> const* miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int> const*, miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)) const::DummyState&&)
Line
Count
Source
662
107
                node(node_), expanded(exp_), state(std::move(state_)) {}
descriptor.cpp:std::optional<(anonymous namespace)::KeyParser> miniscript::Node<unsigned int>::TreeEvalMaybe<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, bool, std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<unsigned int>::ToString<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&, bool&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, unsigned long), std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<unsigned int>::ToString<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&, bool&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, std::span<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, 18446744073709551615ul>)>(bool, std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<unsigned int>::ToString<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&, bool&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, unsigned long), std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<unsigned int>::ToString<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&, bool&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, std::span<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, 18446744073709551615ul>)) const::StackElem::StackElem(miniscript::Node<unsigned int> const&, unsigned long, bool&&)
Line
Count
Source
662
79
                node(node_), expanded(exp_), state(std::move(state_)) {}
descriptor.cpp:std::optional<(anonymous namespace)::ScriptMaker> miniscript::Node<unsigned int>::TreeEvalMaybe<CScript, bool, CScript miniscript::Node<unsigned int>::ToScript<(anonymous namespace)::ScriptMaker>((anonymous namespace)::ScriptMaker const&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, unsigned long), (anonymous namespace)::ScriptMaker miniscript::Node<unsigned int>::TreeEval<CScript, bool, CScript miniscript::Node<unsigned int>::ToScript<(anonymous namespace)::ScriptMaker>((anonymous namespace)::ScriptMaker const&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, unsigned long)&, CScript miniscript::Node<unsigned int>::ToScript<(anonymous namespace)::ScriptMaker>((anonymous namespace)::ScriptMaker const&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, std::span<CScript, 18446744073709551615ul>)>(bool, CScript miniscript::Node<unsigned int>::ToScript<(anonymous namespace)::ScriptMaker>((anonymous namespace)::ScriptMaker const&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, unsigned long)&, CScript miniscript::Node<unsigned int>::ToScript<(anonymous namespace)::ScriptMaker>((anonymous namespace)::ScriptMaker const&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, std::span<CScript, 18446744073709551615ul>)) const::'lambda'(bool&&, miniscript::Node<unsigned int> const&, std::span<CScript, 18446744073709551615ul>)>(bool, CScript miniscript::Node<unsigned int>::ToScript<(anonymous namespace)::ScriptMaker>((anonymous namespace)::ScriptMaker const&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, unsigned long)&, CScript miniscript::Node<unsigned int>::ToScript<(anonymous namespace)::ScriptMaker>((anonymous namespace)::ScriptMaker const&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, std::span<CScript, 18446744073709551615ul>)) const::StackElem::StackElem(miniscript::Node<unsigned int> const&, unsigned long, bool&&)
Line
Count
Source
662
1.66M
                node(node_), expanded(exp_), state(std::move(state_)) {}
descriptor.cpp:std::optional<(anonymous namespace)::StringMaker> miniscript::Node<unsigned int>::TreeEvalMaybe<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, bool, std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<unsigned int>::ToString<(anonymous namespace)::StringMaker>((anonymous namespace)::StringMaker const&, bool&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, unsigned long), std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<unsigned int>::ToString<(anonymous namespace)::StringMaker>((anonymous namespace)::StringMaker const&, bool&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, std::span<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, 18446744073709551615ul>)>(bool, std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<unsigned int>::ToString<(anonymous namespace)::StringMaker>((anonymous namespace)::StringMaker const&, bool&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, unsigned long), std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<unsigned int>::ToString<(anonymous namespace)::StringMaker>((anonymous namespace)::StringMaker const&, bool&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, std::span<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, 18446744073709551615ul>)) const::StackElem::StackElem(miniscript::Node<unsigned int> const&, unsigned long, bool&&)
Line
Count
Source
662
2.97M
                node(node_), expanded(exp_), state(std::move(state_)) {}
std::optional<TapSatisfier> miniscript::Node<XOnlyPubKey>::TreeEvalMaybe<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)) const::DummyState, TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)) const::'lambda'(TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<XOnlyPubKey> const&, unsigned long), TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)) const::'lambda'(TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>), TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)) const::'lambda'(TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<XOnlyPubKey> const&, unsigned long), TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)) const::'lambda'(TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)) const::StackElem::StackElem(miniscript::Node<XOnlyPubKey> const&, unsigned long, TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)) const::DummyState&&)
Line
Count
Source
662
1.98M
                node(node_), expanded(exp_), state(std::move(state_)) {}
std::optional<TapSatisfier> miniscript::Node<XOnlyPubKey>::TreeEvalMaybe<miniscript::internal::InputResult, TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::'lambda'(TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<XOnlyPubKey> const&, unsigned long), TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::'lambda'(TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>), TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::'lambda'(TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<XOnlyPubKey> const&, unsigned long), TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::'lambda'(TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::StackElem::StackElem(miniscript::Node<XOnlyPubKey> const&, unsigned long, TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState&&)
Line
Count
Source
662
1.98M
                node(node_), expanded(exp_), state(std::move(state_)) {}
std::optional<WshSatisfier> miniscript::Node<CPubKey>::TreeEvalMaybe<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, WshSatisfier miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::DummyState, WshSatisfier miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::'lambda'(WshSatisfier miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long), WshSatisfier miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::'lambda'(WshSatisfier miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>), WshSatisfier miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::'lambda'(WshSatisfier miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long), WshSatisfier miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::'lambda'(WshSatisfier miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::StackElem::StackElem(miniscript::Node<CPubKey> const&, unsigned long, WshSatisfier miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::DummyState&&)
Line
Count
Source
662
3.13k
                node(node_), expanded(exp_), state(std::move(state_)) {}
std::optional<WshSatisfier> miniscript::Node<CPubKey>::TreeEvalMaybe<miniscript::internal::InputResult, WshSatisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, WshSatisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::'lambda'(WshSatisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long), WshSatisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::'lambda'(WshSatisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>), WshSatisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::'lambda'(WshSatisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long), WshSatisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::'lambda'(WshSatisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::StackElem::StackElem(miniscript::Node<CPubKey> const&, unsigned long, WshSatisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState&&)
Line
Count
Source
662
3.13k
                node(node_), expanded(exp_), state(std::move(state_)) {}
663
18.5k
        };
664
        /* Stack of tree nodes being explored. */
665
18.5k
        std::vector<StackElem> stack;
666
        /* Results of subtrees so far. Their order and mapping to tree nodes
667
         * is implicitly defined by stack. */
668
18.5k
        std::vector<Result> results;
669
18.5k
        stack.emplace_back(*this, 0, std::move(root_state));
670
671
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
672
         * State variables are omitted for simplicity.
673
         *
674
         * First: stack=[(A,0)] results=[]
675
         *        stack=[(A,1),(B,0)] results=[]
676
         *        stack=[(A,1)] results=[B]
677
         *        stack=[(A,2),(C,0)] results=[B]
678
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
679
         *        stack=[(A,2),(C,1)] results=[B,D]
680
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
681
         *        stack=[(A,2),(C,2)] results=[B,D,E]
682
         *        stack=[(A,2)] results=[B,C]
683
         *        stack=[(A,3),(F,0)] results=[B,C]
684
         *        stack=[(A,3)] results=[B,C,F]
685
         * Final: stack=[] results=[A]
686
         */
687
23.6M
        while (stack.size()) {
688
23.6M
            const Node& node = stack.back().node;
689
23.6M
            if (stack.back().expanded < node.subs.size()) {
690
                /* We encounter a tree node with at least one unexpanded child.
691
                 * Expand it. By the time we hit this node again, the result of
692
                 * that child (and all earlier children) will be at the end of `results`. */
693
11.8M
                size_t child_index = stack.back().expanded++;
694
11.8M
                State child_state = downfn(stack.back().state, node, child_index);
695
11.8M
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
696
11.8M
                continue;
697
11.8M
            }
698
            // Invoke upfn with the last node.subs.size() elements of results as input.
699
23.6M
            assert(results.size() >= node.subs.size());
700
11.8M
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
701
11.8M
                std::span<Result>{results}.last(node.subs.size()))};
702
            // If evaluation returns std::nullopt, abort immediately.
703
11.8M
            if (!result) return {};
704
            // Replace the last node.subs.size() elements of results with the new result.
705
11.8M
            results.erase(results.end() - node.subs.size(), results.end());
706
11.8M
            results.push_back(std::move(*result));
707
11.8M
            stack.pop_back();
708
11.8M
        }
709
        // The final remaining results element is the root result, return it.
710
18.5k
        assert(results.size() >= 1);
711
18.5k
        CHECK_NONFATAL(results.size() == 1);
712
18.5k
        return std::move(results[0]);
713
18.5k
    }
miniscript_tests.cpp:std::optional<(anonymous namespace)::KeyConverter> miniscript::Node<CPubKey>::TreeEvalMaybe<CScript, bool, CScript miniscript::Node<CPubKey>::ToScript<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, unsigned long), (anonymous namespace)::KeyConverter miniscript::Node<CPubKey>::TreeEval<CScript, bool, CScript miniscript::Node<CPubKey>::ToScript<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, unsigned long)&, CScript miniscript::Node<CPubKey>::ToScript<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, std::span<CScript, 18446744073709551615ul>)>(bool, CScript miniscript::Node<CPubKey>::ToScript<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, unsigned long)&, CScript miniscript::Node<CPubKey>::ToScript<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, std::span<CScript, 18446744073709551615ul>)) const::'lambda'(bool&&, miniscript::Node<CPubKey> const&, std::span<CScript, 18446744073709551615ul>)>(bool, CScript miniscript::Node<CPubKey>::ToScript<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, unsigned long)&, CScript miniscript::Node<CPubKey>::ToScript<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, std::span<CScript, 18446744073709551615ul>)) const
Line
Count
Source
653
375
    {
654
        /** Entries of the explicit stack tracked in this algorithm. */
655
375
        struct StackElem
656
375
        {
657
375
            const Node& node; //!< The node being evaluated.
658
375
            size_t expanded; //!< How many children of this node have been expanded.
659
375
            State state; //!< The state for that node.
660
661
375
            StackElem(const Node& node_, size_t exp_, State&& state_) :
662
375
                node(node_), expanded(exp_), state(std::move(state_)) {}
663
375
        };
664
        /* Stack of tree nodes being explored. */
665
375
        std::vector<StackElem> stack;
666
        /* Results of subtrees so far. Their order and mapping to tree nodes
667
         * is implicitly defined by stack. */
668
375
        std::vector<Result> results;
669
375
        stack.emplace_back(*this, 0, std::move(root_state));
670
671
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
672
         * State variables are omitted for simplicity.
673
         *
674
         * First: stack=[(A,0)] results=[]
675
         *        stack=[(A,1),(B,0)] results=[]
676
         *        stack=[(A,1)] results=[B]
677
         *        stack=[(A,2),(C,0)] results=[B]
678
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
679
         *        stack=[(A,2),(C,1)] results=[B,D]
680
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
681
         *        stack=[(A,2),(C,2)] results=[B,D,E]
682
         *        stack=[(A,2)] results=[B,C]
683
         *        stack=[(A,3),(F,0)] results=[B,C]
684
         *        stack=[(A,3)] results=[B,C,F]
685
         * Final: stack=[] results=[A]
686
         */
687
50.8k
        while (stack.size()) {
688
50.4k
            const Node& node = stack.back().node;
689
50.4k
            if (stack.back().expanded < node.subs.size()) {
690
                /* We encounter a tree node with at least one unexpanded child.
691
                 * Expand it. By the time we hit this node again, the result of
692
                 * that child (and all earlier children) will be at the end of `results`. */
693
25.0k
                size_t child_index = stack.back().expanded++;
694
25.0k
                State child_state = downfn(stack.back().state, node, child_index);
695
25.0k
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
696
25.0k
                continue;
697
25.0k
            }
698
            // Invoke upfn with the last node.subs.size() elements of results as input.
699
50.4k
            assert(results.size() >= node.subs.size());
700
25.4k
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
701
25.4k
                std::span<Result>{results}.last(node.subs.size()))};
702
            // If evaluation returns std::nullopt, abort immediately.
703
25.4k
            if (!result) return {};
704
            // Replace the last node.subs.size() elements of results with the new result.
705
25.4k
            results.erase(results.end() - node.subs.size(), results.end());
706
25.4k
            results.push_back(std::move(*result));
707
25.4k
            stack.pop_back();
708
25.4k
        }
709
        // The final remaining results element is the root result, return it.
710
375
        assert(results.size() >= 1);
711
375
        CHECK_NONFATAL(results.size() == 1);
712
375
        return std::move(results[0]);
713
375
    }
miniscript_tests.cpp:std::optional<(anonymous namespace)::Satisfier> miniscript::Node<CPubKey>::TreeEvalMaybe<miniscript::internal::InputResult, (anonymous namespace)::Satisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, (anonymous namespace)::Satisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::Satisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long), (anonymous namespace)::Satisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::Satisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>), (anonymous namespace)::Satisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::Satisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long), (anonymous namespace)::Satisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::Satisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const
Line
Count
Source
653
4.82k
    {
654
        /** Entries of the explicit stack tracked in this algorithm. */
655
4.82k
        struct StackElem
656
4.82k
        {
657
4.82k
            const Node& node; //!< The node being evaluated.
658
4.82k
            size_t expanded; //!< How many children of this node have been expanded.
659
4.82k
            State state; //!< The state for that node.
660
661
4.82k
            StackElem(const Node& node_, size_t exp_, State&& state_) :
662
4.82k
                node(node_), expanded(exp_), state(std::move(state_)) {}
663
4.82k
        };
664
        /* Stack of tree nodes being explored. */
665
4.82k
        std::vector<StackElem> stack;
666
        /* Results of subtrees so far. Their order and mapping to tree nodes
667
         * is implicitly defined by stack. */
668
4.82k
        std::vector<Result> results;
669
4.82k
        stack.emplace_back(*this, 0, std::move(root_state));
670
671
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
672
         * State variables are omitted for simplicity.
673
         *
674
         * First: stack=[(A,0)] results=[]
675
         *        stack=[(A,1),(B,0)] results=[]
676
         *        stack=[(A,1)] results=[B]
677
         *        stack=[(A,2),(C,0)] results=[B]
678
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
679
         *        stack=[(A,2),(C,1)] results=[B,D]
680
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
681
         *        stack=[(A,2),(C,2)] results=[B,D,E]
682
         *        stack=[(A,2)] results=[B,C]
683
         *        stack=[(A,3),(F,0)] results=[B,C]
684
         *        stack=[(A,3)] results=[B,C,F]
685
         * Final: stack=[] results=[A]
686
         */
687
3.23M
        while (stack.size()) {
688
3.22M
            const Node& node = stack.back().node;
689
3.22M
            if (stack.back().expanded < node.subs.size()) {
690
                /* We encounter a tree node with at least one unexpanded child.
691
                 * Expand it. By the time we hit this node again, the result of
692
                 * that child (and all earlier children) will be at the end of `results`. */
693
1.61M
                size_t child_index = stack.back().expanded++;
694
1.61M
                State child_state = downfn(stack.back().state, node, child_index);
695
1.61M
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
696
1.61M
                continue;
697
1.61M
            }
698
            // Invoke upfn with the last node.subs.size() elements of results as input.
699
3.22M
            assert(results.size() >= node.subs.size());
700
1.61M
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
701
1.61M
                std::span<Result>{results}.last(node.subs.size()))};
702
            // If evaluation returns std::nullopt, abort immediately.
703
1.61M
            if (!result) return {};
704
            // Replace the last node.subs.size() elements of results with the new result.
705
1.61M
            results.erase(results.end() - node.subs.size(), results.end());
706
1.61M
            results.push_back(std::move(*result));
707
1.61M
            stack.pop_back();
708
1.61M
        }
709
        // The final remaining results element is the root result, return it.
710
4.82k
        assert(results.size() >= 1);
711
4.82k
        CHECK_NONFATAL(results.size() == 1);
712
4.82k
        return std::move(results[0]);
713
4.82k
    }
miniscript_tests.cpp:std::optional<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)> miniscript::Node<CPubKey>::TreeEvalMaybe<int, (anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&) miniscript::Node<CPubKey>::TreeEval<int, bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)>(bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)) const::DummyState, (anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&) miniscript::Node<CPubKey>::TreeEval<int, bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)>(bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&) miniscript::Node<CPubKey>::TreeEval<int, bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)>(bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long), (anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&) miniscript::Node<CPubKey>::TreeEval<int, bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)>(bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&) miniscript::Node<CPubKey>::TreeEval<int, bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)>(bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)>(bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>), (anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&) miniscript::Node<CPubKey>::TreeEval<int, bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)>(bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&) miniscript::Node<CPubKey>::TreeEval<int, bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)>(bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long), (anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&) miniscript::Node<CPubKey>::TreeEval<int, bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)>(bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&) miniscript::Node<CPubKey>::TreeEval<int, bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)>(bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)) const
Line
Count
Source
653
375
    {
654
        /** Entries of the explicit stack tracked in this algorithm. */
655
375
        struct StackElem
656
375
        {
657
375
            const Node& node; //!< The node being evaluated.
658
375
            size_t expanded; //!< How many children of this node have been expanded.
659
375
            State state; //!< The state for that node.
660
661
375
            StackElem(const Node& node_, size_t exp_, State&& state_) :
662
375
                node(node_), expanded(exp_), state(std::move(state_)) {}
663
375
        };
664
        /* Stack of tree nodes being explored. */
665
375
        std::vector<StackElem> stack;
666
        /* Results of subtrees so far. Their order and mapping to tree nodes
667
         * is implicitly defined by stack. */
668
375
        std::vector<Result> results;
669
375
        stack.emplace_back(*this, 0, std::move(root_state));
670
671
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
672
         * State variables are omitted for simplicity.
673
         *
674
         * First: stack=[(A,0)] results=[]
675
         *        stack=[(A,1),(B,0)] results=[]
676
         *        stack=[(A,1)] results=[B]
677
         *        stack=[(A,2),(C,0)] results=[B]
678
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
679
         *        stack=[(A,2),(C,1)] results=[B,D]
680
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
681
         *        stack=[(A,2),(C,2)] results=[B,D,E]
682
         *        stack=[(A,2)] results=[B,C]
683
         *        stack=[(A,3),(F,0)] results=[B,C]
684
         *        stack=[(A,3)] results=[B,C,F]
685
         * Final: stack=[] results=[A]
686
         */
687
50.8k
        while (stack.size()) {
688
50.4k
            const Node& node = stack.back().node;
689
50.4k
            if (stack.back().expanded < node.subs.size()) {
690
                /* We encounter a tree node with at least one unexpanded child.
691
                 * Expand it. By the time we hit this node again, the result of
692
                 * that child (and all earlier children) will be at the end of `results`. */
693
25.0k
                size_t child_index = stack.back().expanded++;
694
25.0k
                State child_state = downfn(stack.back().state, node, child_index);
695
25.0k
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
696
25.0k
                continue;
697
25.0k
            }
698
            // Invoke upfn with the last node.subs.size() elements of results as input.
699
50.4k
            assert(results.size() >= node.subs.size());
700
25.4k
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
701
25.4k
                std::span<Result>{results}.last(node.subs.size()))};
702
            // If evaluation returns std::nullopt, abort immediately.
703
25.4k
            if (!result) return {};
704
            // Replace the last node.subs.size() elements of results with the new result.
705
25.4k
            results.erase(results.end() - node.subs.size(), results.end());
706
25.4k
            results.push_back(std::move(*result));
707
25.4k
            stack.pop_back();
708
25.4k
        }
709
        // The final remaining results element is the root result, return it.
710
375
        assert(results.size() >= 1);
711
375
        CHECK_NONFATAL(results.size() == 1);
712
375
        return std::move(results[0]);
713
375
    }
miniscript_tests.cpp:std::optional<(anonymous namespace)::KeyConverter> miniscript::Node<CPubKey>::TreeEvalMaybe<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, (anonymous namespace)::KeyConverter miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::DummyState, (anonymous namespace)::KeyConverter miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::KeyConverter miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long), (anonymous namespace)::KeyConverter miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::KeyConverter miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>), (anonymous namespace)::KeyConverter miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::KeyConverter miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long), (anonymous namespace)::KeyConverter miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::KeyConverter miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const
Line
Count
Source
653
313
    {
654
        /** Entries of the explicit stack tracked in this algorithm. */
655
313
        struct StackElem
656
313
        {
657
313
            const Node& node; //!< The node being evaluated.
658
313
            size_t expanded; //!< How many children of this node have been expanded.
659
313
            State state; //!< The state for that node.
660
661
313
            StackElem(const Node& node_, size_t exp_, State&& state_) :
662
313
                node(node_), expanded(exp_), state(std::move(state_)) {}
663
313
        };
664
        /* Stack of tree nodes being explored. */
665
313
        std::vector<StackElem> stack;
666
        /* Results of subtrees so far. Their order and mapping to tree nodes
667
         * is implicitly defined by stack. */
668
313
        std::vector<Result> results;
669
313
        stack.emplace_back(*this, 0, std::move(root_state));
670
671
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
672
         * State variables are omitted for simplicity.
673
         *
674
         * First: stack=[(A,0)] results=[]
675
         *        stack=[(A,1),(B,0)] results=[]
676
         *        stack=[(A,1)] results=[B]
677
         *        stack=[(A,2),(C,0)] results=[B]
678
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
679
         *        stack=[(A,2),(C,1)] results=[B,D]
680
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
681
         *        stack=[(A,2),(C,2)] results=[B,D,E]
682
         *        stack=[(A,2)] results=[B,C]
683
         *        stack=[(A,3),(F,0)] results=[B,C]
684
         *        stack=[(A,3)] results=[B,C,F]
685
         * Final: stack=[] results=[A]
686
         */
687
46.5k
        while (stack.size()) {
688
46.1k
            const Node& node = stack.back().node;
689
46.1k
            if (stack.back().expanded < node.subs.size()) {
690
                /* We encounter a tree node with at least one unexpanded child.
691
                 * Expand it. By the time we hit this node again, the result of
692
                 * that child (and all earlier children) will be at the end of `results`. */
693
22.9k
                size_t child_index = stack.back().expanded++;
694
22.9k
                State child_state = downfn(stack.back().state, node, child_index);
695
22.9k
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
696
22.9k
                continue;
697
22.9k
            }
698
            // Invoke upfn with the last node.subs.size() elements of results as input.
699
46.1k
            assert(results.size() >= node.subs.size());
700
23.2k
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
701
23.2k
                std::span<Result>{results}.last(node.subs.size()))};
702
            // If evaluation returns std::nullopt, abort immediately.
703
23.2k
            if (!result) return {};
704
            // Replace the last node.subs.size() elements of results with the new result.
705
23.2k
            results.erase(results.end() - node.subs.size(), results.end());
706
23.2k
            results.push_back(std::move(*result));
707
23.2k
            stack.pop_back();
708
23.2k
        }
709
        // The final remaining results element is the root result, return it.
710
313
        assert(results.size() >= 1);
711
313
        CHECK_NONFATAL(results.size() == 1);
712
313
        return std::move(results[0]);
713
313
    }
std::optional<miniscript::Node<CPubKey> const*> miniscript::Node<CPubKey>::TreeEvalMaybe<miniscript::Node<CPubKey> const*, miniscript::Node<CPubKey> const* miniscript::Node<CPubKey>::TreeEval<miniscript::Node<CPubKey> const*, miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)>(miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const* miniscript::Node<CPubKey>::TreeEval<miniscript::Node<CPubKey> const*, miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)>(miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)) const::'lambda'(miniscript::Node<CPubKey> const* miniscript::Node<CPubKey>::TreeEval<miniscript::Node<CPubKey> const*, miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)>(miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long), miniscript::Node<CPubKey> const* miniscript::Node<CPubKey>::TreeEval<miniscript::Node<CPubKey> const*, miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)>(miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)) const::'lambda'(miniscript::Node<CPubKey> const* miniscript::Node<CPubKey>::TreeEval<miniscript::Node<CPubKey> const*, miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)>(miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)>(miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>), miniscript::Node<CPubKey> const* miniscript::Node<CPubKey>::TreeEval<miniscript::Node<CPubKey> const*, miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)>(miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)) const::'lambda'(miniscript::Node<CPubKey> const* miniscript::Node<CPubKey>::TreeEval<miniscript::Node<CPubKey> const*, miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)>(miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long), miniscript::Node<CPubKey> const* miniscript::Node<CPubKey>::TreeEval<miniscript::Node<CPubKey> const*, miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)>(miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)) const::'lambda'(miniscript::Node<CPubKey> const* miniscript::Node<CPubKey>::TreeEval<miniscript::Node<CPubKey> const*, miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)>(miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)) const
Line
Count
Source
653
1
    {
654
        /** Entries of the explicit stack tracked in this algorithm. */
655
1
        struct StackElem
656
1
        {
657
1
            const Node& node; //!< The node being evaluated.
658
1
            size_t expanded; //!< How many children of this node have been expanded.
659
1
            State state; //!< The state for that node.
660
661
1
            StackElem(const Node& node_, size_t exp_, State&& state_) :
662
1
                node(node_), expanded(exp_), state(std::move(state_)) {}
663
1
        };
664
        /* Stack of tree nodes being explored. */
665
1
        std::vector<StackElem> stack;
666
        /* Results of subtrees so far. Their order and mapping to tree nodes
667
         * is implicitly defined by stack. */
668
1
        std::vector<Result> results;
669
1
        stack.emplace_back(*this, 0, std::move(root_state));
670
671
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
672
         * State variables are omitted for simplicity.
673
         *
674
         * First: stack=[(A,0)] results=[]
675
         *        stack=[(A,1),(B,0)] results=[]
676
         *        stack=[(A,1)] results=[B]
677
         *        stack=[(A,2),(C,0)] results=[B]
678
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
679
         *        stack=[(A,2),(C,1)] results=[B,D]
680
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
681
         *        stack=[(A,2),(C,2)] results=[B,D,E]
682
         *        stack=[(A,2)] results=[B,C]
683
         *        stack=[(A,3),(F,0)] results=[B,C]
684
         *        stack=[(A,3)] results=[B,C,F]
685
         * Final: stack=[] results=[A]
686
         */
687
14
        while (stack.size()) {
688
13
            const Node& node = stack.back().node;
689
13
            if (stack.back().expanded < node.subs.size()) {
690
                /* We encounter a tree node with at least one unexpanded child.
691
                 * Expand it. By the time we hit this node again, the result of
692
                 * that child (and all earlier children) will be at the end of `results`. */
693
6
                size_t child_index = stack.back().expanded++;
694
6
                State child_state = downfn(stack.back().state, node, child_index);
695
6
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
696
6
                continue;
697
6
            }
698
            // Invoke upfn with the last node.subs.size() elements of results as input.
699
13
            assert(results.size() >= node.subs.size());
700
7
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
701
7
                std::span<Result>{results}.last(node.subs.size()))};
702
            // If evaluation returns std::nullopt, abort immediately.
703
7
            if (!result) return {};
704
            // Replace the last node.subs.size() elements of results with the new result.
705
7
            results.erase(results.end() - node.subs.size(), results.end());
706
7
            results.push_back(std::move(*result));
707
7
            stack.pop_back();
708
7
        }
709
        // The final remaining results element is the root result, return it.
710
1
        assert(results.size() >= 1);
711
1
        CHECK_NONFATAL(results.size() == 1);
712
1
        return std::move(results[0]);
713
1
    }
miniscript_tests.cpp:std::optional<(anonymous namespace)::KeyConverter> miniscript::Node<CPubKey>::TreeEvalMaybe<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, bool, std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<CPubKey>::ToString<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&, bool&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, unsigned long), std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<CPubKey>::ToString<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&, bool&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, std::span<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, 18446744073709551615ul>)>(bool, std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<CPubKey>::ToString<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&, bool&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, unsigned long), std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<CPubKey>::ToString<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&, bool&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, std::span<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, 18446744073709551615ul>)) const
Line
Count
Source
653
1
    {
654
        /** Entries of the explicit stack tracked in this algorithm. */
655
1
        struct StackElem
656
1
        {
657
1
            const Node& node; //!< The node being evaluated.
658
1
            size_t expanded; //!< How many children of this node have been expanded.
659
1
            State state; //!< The state for that node.
660
661
1
            StackElem(const Node& node_, size_t exp_, State&& state_) :
662
1
                node(node_), expanded(exp_), state(std::move(state_)) {}
663
1
        };
664
        /* Stack of tree nodes being explored. */
665
1
        std::vector<StackElem> stack;
666
        /* Results of subtrees so far. Their order and mapping to tree nodes
667
         * is implicitly defined by stack. */
668
1
        std::vector<Result> results;
669
1
        stack.emplace_back(*this, 0, std::move(root_state));
670
671
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
672
         * State variables are omitted for simplicity.
673
         *
674
         * First: stack=[(A,0)] results=[]
675
         *        stack=[(A,1),(B,0)] results=[]
676
         *        stack=[(A,1)] results=[B]
677
         *        stack=[(A,2),(C,0)] results=[B]
678
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
679
         *        stack=[(A,2),(C,1)] results=[B,D]
680
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
681
         *        stack=[(A,2),(C,2)] results=[B,D,E]
682
         *        stack=[(A,2)] results=[B,C]
683
         *        stack=[(A,3),(F,0)] results=[B,C]
684
         *        stack=[(A,3)] results=[B,C,F]
685
         * Final: stack=[] results=[A]
686
         */
687
8
        while (stack.size()) {
688
7
            const Node& node = stack.back().node;
689
7
            if (stack.back().expanded < node.subs.size()) {
690
                /* We encounter a tree node with at least one unexpanded child.
691
                 * Expand it. By the time we hit this node again, the result of
692
                 * that child (and all earlier children) will be at the end of `results`. */
693
3
                size_t child_index = stack.back().expanded++;
694
3
                State child_state = downfn(stack.back().state, node, child_index);
695
3
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
696
3
                continue;
697
3
            }
698
            // Invoke upfn with the last node.subs.size() elements of results as input.
699
7
            assert(results.size() >= node.subs.size());
700
4
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
701
4
                std::span<Result>{results}.last(node.subs.size()))};
702
            // If evaluation returns std::nullopt, abort immediately.
703
4
            if (!result) return {};
704
            // Replace the last node.subs.size() elements of results with the new result.
705
4
            results.erase(results.end() - node.subs.size(), results.end());
706
4
            results.push_back(std::move(*result));
707
4
            stack.pop_back();
708
4
        }
709
        // The final remaining results element is the root result, return it.
710
1
        assert(results.size() >= 1);
711
1
        CHECK_NONFATAL(results.size() == 1);
712
1
        return std::move(results[0]);
713
1
    }
std::optional<miniscript::Node<unsigned int>> miniscript::Node<unsigned int>::TreeEvalMaybe<miniscript::Node<unsigned int>, miniscript::Node<unsigned int> miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int>, miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int>, miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)) const::'lambda'(miniscript::Node<unsigned int> miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int>, miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, unsigned long), miniscript::Node<unsigned int> miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int>, miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)) const::'lambda'(miniscript::Node<unsigned int> miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int>, miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>), miniscript::Node<unsigned int> miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int>, miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)) const::'lambda'(miniscript::Node<unsigned int> miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int>, miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, unsigned long), miniscript::Node<unsigned int> miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int>, miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)) const::'lambda'(miniscript::Node<unsigned int> miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int>, miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)) const
Line
Count
Source
653
193
    {
654
        /** Entries of the explicit stack tracked in this algorithm. */
655
193
        struct StackElem
656
193
        {
657
193
            const Node& node; //!< The node being evaluated.
658
193
            size_t expanded; //!< How many children of this node have been expanded.
659
193
            State state; //!< The state for that node.
660
661
193
            StackElem(const Node& node_, size_t exp_, State&& state_) :
662
193
                node(node_), expanded(exp_), state(std::move(state_)) {}
663
193
        };
664
        /* Stack of tree nodes being explored. */
665
193
        std::vector<StackElem> stack;
666
        /* Results of subtrees so far. Their order and mapping to tree nodes
667
         * is implicitly defined by stack. */
668
193
        std::vector<Result> results;
669
193
        stack.emplace_back(*this, 0, std::move(root_state));
670
671
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
672
         * State variables are omitted for simplicity.
673
         *
674
         * First: stack=[(A,0)] results=[]
675
         *        stack=[(A,1),(B,0)] results=[]
676
         *        stack=[(A,1)] results=[B]
677
         *        stack=[(A,2),(C,0)] results=[B]
678
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
679
         *        stack=[(A,2),(C,1)] results=[B,D]
680
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
681
         *        stack=[(A,2),(C,2)] results=[B,D,E]
682
         *        stack=[(A,2)] results=[B,C]
683
         *        stack=[(A,3),(F,0)] results=[B,C]
684
         *        stack=[(A,3)] results=[B,C,F]
685
         * Final: stack=[] results=[A]
686
         */
687
1.06M
        while (stack.size()) {
688
1.06M
            const Node& node = stack.back().node;
689
1.06M
            if (stack.back().expanded < node.subs.size()) {
690
                /* We encounter a tree node with at least one unexpanded child.
691
                 * Expand it. By the time we hit this node again, the result of
692
                 * that child (and all earlier children) will be at the end of `results`. */
693
530k
                size_t child_index = stack.back().expanded++;
694
530k
                State child_state = downfn(stack.back().state, node, child_index);
695
530k
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
696
530k
                continue;
697
530k
            }
698
            // Invoke upfn with the last node.subs.size() elements of results as input.
699
1.06M
            assert(results.size() >= node.subs.size());
700
531k
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
701
531k
                std::span<Result>{results}.last(node.subs.size()))};
702
            // If evaluation returns std::nullopt, abort immediately.
703
531k
            if (!result) return {};
704
            // Replace the last node.subs.size() elements of results with the new result.
705
531k
            results.erase(results.end() - node.subs.size(), results.end());
706
531k
            results.push_back(std::move(*result));
707
531k
            stack.pop_back();
708
531k
        }
709
        // The final remaining results element is the root result, return it.
710
193
        assert(results.size() >= 1);
711
193
        CHECK_NONFATAL(results.size() == 1);
712
193
        return std::move(results[0]);
713
193
    }
descriptor.cpp:std::optional<(anonymous namespace)::KeyParser> miniscript::Node<unsigned int>::TreeEvalMaybe<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, (anonymous namespace)::KeyParser miniscript::Node<unsigned int>::TreeEval<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)>(void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)) const::DummyState, (anonymous namespace)::KeyParser miniscript::Node<unsigned int>::TreeEval<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)>(void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::KeyParser miniscript::Node<unsigned int>::TreeEval<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)>(void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, unsigned long), (anonymous namespace)::KeyParser miniscript::Node<unsigned int>::TreeEval<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)>(void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::KeyParser miniscript::Node<unsigned int>::TreeEval<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)>(void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)>(void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>), (anonymous namespace)::KeyParser miniscript::Node<unsigned int>::TreeEval<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)>(void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::KeyParser miniscript::Node<unsigned int>::TreeEval<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)>(void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, unsigned long), (anonymous namespace)::KeyParser miniscript::Node<unsigned int>::TreeEval<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)>(void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::KeyParser miniscript::Node<unsigned int>::TreeEval<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)>(void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)) const
Line
Count
Source
653
788
    {
654
        /** Entries of the explicit stack tracked in this algorithm. */
655
788
        struct StackElem
656
788
        {
657
788
            const Node& node; //!< The node being evaluated.
658
788
            size_t expanded; //!< How many children of this node have been expanded.
659
788
            State state; //!< The state for that node.
660
661
788
            StackElem(const Node& node_, size_t exp_, State&& state_) :
662
788
                node(node_), expanded(exp_), state(std::move(state_)) {}
663
788
        };
664
        /* Stack of tree nodes being explored. */
665
788
        std::vector<StackElem> stack;
666
        /* Results of subtrees so far. Their order and mapping to tree nodes
667
         * is implicitly defined by stack. */
668
788
        std::vector<Result> results;
669
788
        stack.emplace_back(*this, 0, std::move(root_state));
670
671
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
672
         * State variables are omitted for simplicity.
673
         *
674
         * First: stack=[(A,0)] results=[]
675
         *        stack=[(A,1),(B,0)] results=[]
676
         *        stack=[(A,1)] results=[B]
677
         *        stack=[(A,2),(C,0)] results=[B]
678
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
679
         *        stack=[(A,2),(C,1)] results=[B,D]
680
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
681
         *        stack=[(A,2),(C,2)] results=[B,D,E]
682
         *        stack=[(A,2)] results=[B,C]
683
         *        stack=[(A,3),(F,0)] results=[B,C]
684
         *        stack=[(A,3)] results=[B,C,F]
685
         * Final: stack=[] results=[A]
686
         */
687
1.99M
        while (stack.size()) {
688
1.99M
            const Node& node = stack.back().node;
689
1.99M
            if (stack.back().expanded < node.subs.size()) {
690
                /* We encounter a tree node with at least one unexpanded child.
691
                 * Expand it. By the time we hit this node again, the result of
692
                 * that child (and all earlier children) will be at the end of `results`. */
693
994k
                size_t child_index = stack.back().expanded++;
694
994k
                State child_state = downfn(stack.back().state, node, child_index);
695
994k
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
696
994k
                continue;
697
994k
            }
698
            // Invoke upfn with the last node.subs.size() elements of results as input.
699
1.99M
            assert(results.size() >= node.subs.size());
700
995k
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
701
995k
                std::span<Result>{results}.last(node.subs.size()))};
702
            // If evaluation returns std::nullopt, abort immediately.
703
995k
            if (!result) return {};
704
            // Replace the last node.subs.size() elements of results with the new result.
705
995k
            results.erase(results.end() - node.subs.size(), results.end());
706
995k
            results.push_back(std::move(*result));
707
995k
            stack.pop_back();
708
995k
        }
709
        // The final remaining results element is the root result, return it.
710
788
        assert(results.size() >= 1);
711
788
        CHECK_NONFATAL(results.size() == 1);
712
788
        return std::move(results[0]);
713
788
    }
std::optional<miniscript::Node<unsigned int> const*> miniscript::Node<unsigned int>::TreeEvalMaybe<miniscript::Node<unsigned int> const*, miniscript::Node<unsigned int> const* miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int> const*, miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const* miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int> const*, miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)) const::'lambda'(miniscript::Node<unsigned int> const* miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int> const*, miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, unsigned long), miniscript::Node<unsigned int> const* miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int> const*, miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)) const::'lambda'(miniscript::Node<unsigned int> const* miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int> const*, miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>), miniscript::Node<unsigned int> const* miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int> const*, miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)) const::'lambda'(miniscript::Node<unsigned int> const* miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int> const*, miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, unsigned long), miniscript::Node<unsigned int> const* miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int> const*, miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)) const::'lambda'(miniscript::Node<unsigned int> const* miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int> const*, miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)) const
Line
Count
Source
653
14
    {
654
        /** Entries of the explicit stack tracked in this algorithm. */
655
14
        struct StackElem
656
14
        {
657
14
            const Node& node; //!< The node being evaluated.
658
14
            size_t expanded; //!< How many children of this node have been expanded.
659
14
            State state; //!< The state for that node.
660
661
14
            StackElem(const Node& node_, size_t exp_, State&& state_) :
662
14
                node(node_), expanded(exp_), state(std::move(state_)) {}
663
14
        };
664
        /* Stack of tree nodes being explored. */
665
14
        std::vector<StackElem> stack;
666
        /* Results of subtrees so far. Their order and mapping to tree nodes
667
         * is implicitly defined by stack. */
668
14
        std::vector<Result> results;
669
14
        stack.emplace_back(*this, 0, std::move(root_state));
670
671
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
672
         * State variables are omitted for simplicity.
673
         *
674
         * First: stack=[(A,0)] results=[]
675
         *        stack=[(A,1),(B,0)] results=[]
676
         *        stack=[(A,1)] results=[B]
677
         *        stack=[(A,2),(C,0)] results=[B]
678
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
679
         *        stack=[(A,2),(C,1)] results=[B,D]
680
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
681
         *        stack=[(A,2),(C,2)] results=[B,D,E]
682
         *        stack=[(A,2)] results=[B,C]
683
         *        stack=[(A,3),(F,0)] results=[B,C]
684
         *        stack=[(A,3)] results=[B,C,F]
685
         * Final: stack=[] results=[A]
686
         */
687
214
        while (stack.size()) {
688
200
            const Node& node = stack.back().node;
689
200
            if (stack.back().expanded < node.subs.size()) {
690
                /* We encounter a tree node with at least one unexpanded child.
691
                 * Expand it. By the time we hit this node again, the result of
692
                 * that child (and all earlier children) will be at the end of `results`. */
693
93
                size_t child_index = stack.back().expanded++;
694
93
                State child_state = downfn(stack.back().state, node, child_index);
695
93
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
696
93
                continue;
697
93
            }
698
            // Invoke upfn with the last node.subs.size() elements of results as input.
699
200
            assert(results.size() >= node.subs.size());
700
107
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
701
107
                std::span<Result>{results}.last(node.subs.size()))};
702
            // If evaluation returns std::nullopt, abort immediately.
703
107
            if (!result) return {};
704
            // Replace the last node.subs.size() elements of results with the new result.
705
107
            results.erase(results.end() - node.subs.size(), results.end());
706
107
            results.push_back(std::move(*result));
707
107
            stack.pop_back();
708
107
        }
709
        // The final remaining results element is the root result, return it.
710
14
        assert(results.size() >= 1);
711
14
        CHECK_NONFATAL(results.size() == 1);
712
14
        return std::move(results[0]);
713
14
    }
descriptor.cpp:std::optional<(anonymous namespace)::KeyParser> miniscript::Node<unsigned int>::TreeEvalMaybe<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, bool, std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<unsigned int>::ToString<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&, bool&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, unsigned long), std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<unsigned int>::ToString<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&, bool&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, std::span<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, 18446744073709551615ul>)>(bool, std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<unsigned int>::ToString<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&, bool&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, unsigned long), std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<unsigned int>::ToString<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&, bool&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, std::span<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, 18446744073709551615ul>)) const
Line
Count
Source
653
14
    {
654
        /** Entries of the explicit stack tracked in this algorithm. */
655
14
        struct StackElem
656
14
        {
657
14
            const Node& node; //!< The node being evaluated.
658
14
            size_t expanded; //!< How many children of this node have been expanded.
659
14
            State state; //!< The state for that node.
660
661
14
            StackElem(const Node& node_, size_t exp_, State&& state_) :
662
14
                node(node_), expanded(exp_), state(std::move(state_)) {}
663
14
        };
664
        /* Stack of tree nodes being explored. */
665
14
        std::vector<StackElem> stack;
666
        /* Results of subtrees so far. Their order and mapping to tree nodes
667
         * is implicitly defined by stack. */
668
14
        std::vector<Result> results;
669
14
        stack.emplace_back(*this, 0, std::move(root_state));
670
671
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
672
         * State variables are omitted for simplicity.
673
         *
674
         * First: stack=[(A,0)] results=[]
675
         *        stack=[(A,1),(B,0)] results=[]
676
         *        stack=[(A,1)] results=[B]
677
         *        stack=[(A,2),(C,0)] results=[B]
678
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
679
         *        stack=[(A,2),(C,1)] results=[B,D]
680
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
681
         *        stack=[(A,2),(C,2)] results=[B,D,E]
682
         *        stack=[(A,2)] results=[B,C]
683
         *        stack=[(A,3),(F,0)] results=[B,C]
684
         *        stack=[(A,3)] results=[B,C,F]
685
         * Final: stack=[] results=[A]
686
         */
687
158
        while (stack.size()) {
688
144
            const Node& node = stack.back().node;
689
144
            if (stack.back().expanded < node.subs.size()) {
690
                /* We encounter a tree node with at least one unexpanded child.
691
                 * Expand it. By the time we hit this node again, the result of
692
                 * that child (and all earlier children) will be at the end of `results`. */
693
65
                size_t child_index = stack.back().expanded++;
694
65
                State child_state = downfn(stack.back().state, node, child_index);
695
65
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
696
65
                continue;
697
65
            }
698
            // Invoke upfn with the last node.subs.size() elements of results as input.
699
144
            assert(results.size() >= node.subs.size());
700
79
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
701
79
                std::span<Result>{results}.last(node.subs.size()))};
702
            // If evaluation returns std::nullopt, abort immediately.
703
79
            if (!result) return {};
704
            // Replace the last node.subs.size() elements of results with the new result.
705
79
            results.erase(results.end() - node.subs.size(), results.end());
706
79
            results.push_back(std::move(*result));
707
79
            stack.pop_back();
708
79
        }
709
        // The final remaining results element is the root result, return it.
710
14
        assert(results.size() >= 1);
711
14
        CHECK_NONFATAL(results.size() == 1);
712
14
        return std::move(results[0]);
713
14
    }
descriptor.cpp:std::optional<(anonymous namespace)::ScriptMaker> miniscript::Node<unsigned int>::TreeEvalMaybe<CScript, bool, CScript miniscript::Node<unsigned int>::ToScript<(anonymous namespace)::ScriptMaker>((anonymous namespace)::ScriptMaker const&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, unsigned long), (anonymous namespace)::ScriptMaker miniscript::Node<unsigned int>::TreeEval<CScript, bool, CScript miniscript::Node<unsigned int>::ToScript<(anonymous namespace)::ScriptMaker>((anonymous namespace)::ScriptMaker const&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, unsigned long)&, CScript miniscript::Node<unsigned int>::ToScript<(anonymous namespace)::ScriptMaker>((anonymous namespace)::ScriptMaker const&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, std::span<CScript, 18446744073709551615ul>)>(bool, CScript miniscript::Node<unsigned int>::ToScript<(anonymous namespace)::ScriptMaker>((anonymous namespace)::ScriptMaker const&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, unsigned long)&, CScript miniscript::Node<unsigned int>::ToScript<(anonymous namespace)::ScriptMaker>((anonymous namespace)::ScriptMaker const&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, std::span<CScript, 18446744073709551615ul>)) const::'lambda'(bool&&, miniscript::Node<unsigned int> const&, std::span<CScript, 18446744073709551615ul>)>(bool, CScript miniscript::Node<unsigned int>::ToScript<(anonymous namespace)::ScriptMaker>((anonymous namespace)::ScriptMaker const&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, unsigned long)&, CScript miniscript::Node<unsigned int>::ToScript<(anonymous namespace)::ScriptMaker>((anonymous namespace)::ScriptMaker const&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, std::span<CScript, 18446744073709551615ul>)) const
Line
Count
Source
653
1.50k
    {
654
        /** Entries of the explicit stack tracked in this algorithm. */
655
1.50k
        struct StackElem
656
1.50k
        {
657
1.50k
            const Node& node; //!< The node being evaluated.
658
1.50k
            size_t expanded; //!< How many children of this node have been expanded.
659
1.50k
            State state; //!< The state for that node.
660
661
1.50k
            StackElem(const Node& node_, size_t exp_, State&& state_) :
662
1.50k
                node(node_), expanded(exp_), state(std::move(state_)) {}
663
1.50k
        };
664
        /* Stack of tree nodes being explored. */
665
1.50k
        std::vector<StackElem> stack;
666
        /* Results of subtrees so far. Their order and mapping to tree nodes
667
         * is implicitly defined by stack. */
668
1.50k
        std::vector<Result> results;
669
1.50k
        stack.emplace_back(*this, 0, std::move(root_state));
670
671
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
672
         * State variables are omitted for simplicity.
673
         *
674
         * First: stack=[(A,0)] results=[]
675
         *        stack=[(A,1),(B,0)] results=[]
676
         *        stack=[(A,1)] results=[B]
677
         *        stack=[(A,2),(C,0)] results=[B]
678
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
679
         *        stack=[(A,2),(C,1)] results=[B,D]
680
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
681
         *        stack=[(A,2),(C,2)] results=[B,D,E]
682
         *        stack=[(A,2)] results=[B,C]
683
         *        stack=[(A,3),(F,0)] results=[B,C]
684
         *        stack=[(A,3)] results=[B,C,F]
685
         * Final: stack=[] results=[A]
686
         */
687
3.32M
        while (stack.size()) {
688
3.32M
            const Node& node = stack.back().node;
689
3.32M
            if (stack.back().expanded < node.subs.size()) {
690
                /* We encounter a tree node with at least one unexpanded child.
691
                 * Expand it. By the time we hit this node again, the result of
692
                 * that child (and all earlier children) will be at the end of `results`. */
693
1.66M
                size_t child_index = stack.back().expanded++;
694
1.66M
                State child_state = downfn(stack.back().state, node, child_index);
695
1.66M
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
696
1.66M
                continue;
697
1.66M
            }
698
            // Invoke upfn with the last node.subs.size() elements of results as input.
699
3.32M
            assert(results.size() >= node.subs.size());
700
1.66M
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
701
1.66M
                std::span<Result>{results}.last(node.subs.size()))};
702
            // If evaluation returns std::nullopt, abort immediately.
703
1.66M
            if (!result) return {};
704
            // Replace the last node.subs.size() elements of results with the new result.
705
1.66M
            results.erase(results.end() - node.subs.size(), results.end());
706
1.66M
            results.push_back(std::move(*result));
707
1.66M
            stack.pop_back();
708
1.66M
        }
709
        // The final remaining results element is the root result, return it.
710
1.50k
        assert(results.size() >= 1);
711
1.50k
        CHECK_NONFATAL(results.size() == 1);
712
1.50k
        return std::move(results[0]);
713
1.50k
    }
descriptor.cpp:std::optional<(anonymous namespace)::StringMaker> miniscript::Node<unsigned int>::TreeEvalMaybe<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, bool, std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<unsigned int>::ToString<(anonymous namespace)::StringMaker>((anonymous namespace)::StringMaker const&, bool&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, unsigned long), std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<unsigned int>::ToString<(anonymous namespace)::StringMaker>((anonymous namespace)::StringMaker const&, bool&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, std::span<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, 18446744073709551615ul>)>(bool, std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<unsigned int>::ToString<(anonymous namespace)::StringMaker>((anonymous namespace)::StringMaker const&, bool&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, unsigned long), std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<unsigned int>::ToString<(anonymous namespace)::StringMaker>((anonymous namespace)::StringMaker const&, bool&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, std::span<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, 18446744073709551615ul>)) const
Line
Count
Source
653
1.10k
    {
654
        /** Entries of the explicit stack tracked in this algorithm. */
655
1.10k
        struct StackElem
656
1.10k
        {
657
1.10k
            const Node& node; //!< The node being evaluated.
658
1.10k
            size_t expanded; //!< How many children of this node have been expanded.
659
1.10k
            State state; //!< The state for that node.
660
661
1.10k
            StackElem(const Node& node_, size_t exp_, State&& state_) :
662
1.10k
                node(node_), expanded(exp_), state(std::move(state_)) {}
663
1.10k
        };
664
        /* Stack of tree nodes being explored. */
665
1.10k
        std::vector<StackElem> stack;
666
        /* Results of subtrees so far. Their order and mapping to tree nodes
667
         * is implicitly defined by stack. */
668
1.10k
        std::vector<Result> results;
669
1.10k
        stack.emplace_back(*this, 0, std::move(root_state));
670
671
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
672
         * State variables are omitted for simplicity.
673
         *
674
         * First: stack=[(A,0)] results=[]
675
         *        stack=[(A,1),(B,0)] results=[]
676
         *        stack=[(A,1)] results=[B]
677
         *        stack=[(A,2),(C,0)] results=[B]
678
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
679
         *        stack=[(A,2),(C,1)] results=[B,D]
680
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
681
         *        stack=[(A,2),(C,2)] results=[B,D,E]
682
         *        stack=[(A,2)] results=[B,C]
683
         *        stack=[(A,3),(F,0)] results=[B,C]
684
         *        stack=[(A,3)] results=[B,C,F]
685
         * Final: stack=[] results=[A]
686
         */
687
5.95M
        while (stack.size()) {
688
5.95M
            const Node& node = stack.back().node;
689
5.95M
            if (stack.back().expanded < node.subs.size()) {
690
                /* We encounter a tree node with at least one unexpanded child.
691
                 * Expand it. By the time we hit this node again, the result of
692
                 * that child (and all earlier children) will be at the end of `results`. */
693
2.97M
                size_t child_index = stack.back().expanded++;
694
2.97M
                State child_state = downfn(stack.back().state, node, child_index);
695
2.97M
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
696
2.97M
                continue;
697
2.97M
            }
698
            // Invoke upfn with the last node.subs.size() elements of results as input.
699
5.95M
            assert(results.size() >= node.subs.size());
700
2.97M
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
701
2.97M
                std::span<Result>{results}.last(node.subs.size()))};
702
            // If evaluation returns std::nullopt, abort immediately.
703
2.97M
            if (!result) return {};
704
            // Replace the last node.subs.size() elements of results with the new result.
705
2.97M
            results.erase(results.end() - node.subs.size(), results.end());
706
2.97M
            results.push_back(std::move(*result));
707
2.97M
            stack.pop_back();
708
2.97M
        }
709
        // The final remaining results element is the root result, return it.
710
1.10k
        assert(results.size() >= 1);
711
1.10k
        CHECK_NONFATAL(results.size() == 1);
712
1.10k
        return std::move(results[0]);
713
1.10k
    }
std::optional<TapSatisfier> miniscript::Node<XOnlyPubKey>::TreeEvalMaybe<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)) const::DummyState, TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)) const::'lambda'(TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<XOnlyPubKey> const&, unsigned long), TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)) const::'lambda'(TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>), TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)) const::'lambda'(TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<XOnlyPubKey> const&, unsigned long), TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)) const::'lambda'(TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)) const
Line
Count
Source
653
4.32k
    {
654
        /** Entries of the explicit stack tracked in this algorithm. */
655
4.32k
        struct StackElem
656
4.32k
        {
657
4.32k
            const Node& node; //!< The node being evaluated.
658
4.32k
            size_t expanded; //!< How many children of this node have been expanded.
659
4.32k
            State state; //!< The state for that node.
660
661
4.32k
            StackElem(const Node& node_, size_t exp_, State&& state_) :
662
4.32k
                node(node_), expanded(exp_), state(std::move(state_)) {}
663
4.32k
        };
664
        /* Stack of tree nodes being explored. */
665
4.32k
        std::vector<StackElem> stack;
666
        /* Results of subtrees so far. Their order and mapping to tree nodes
667
         * is implicitly defined by stack. */
668
4.32k
        std::vector<Result> results;
669
4.32k
        stack.emplace_back(*this, 0, std::move(root_state));
670
671
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
672
         * State variables are omitted for simplicity.
673
         *
674
         * First: stack=[(A,0)] results=[]
675
         *        stack=[(A,1),(B,0)] results=[]
676
         *        stack=[(A,1)] results=[B]
677
         *        stack=[(A,2),(C,0)] results=[B]
678
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
679
         *        stack=[(A,2),(C,1)] results=[B,D]
680
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
681
         *        stack=[(A,2),(C,2)] results=[B,D,E]
682
         *        stack=[(A,2)] results=[B,C]
683
         *        stack=[(A,3),(F,0)] results=[B,C]
684
         *        stack=[(A,3)] results=[B,C,F]
685
         * Final: stack=[] results=[A]
686
         */
687
3.97M
        while (stack.size()) {
688
3.97M
            const Node& node = stack.back().node;
689
3.97M
            if (stack.back().expanded < node.subs.size()) {
690
                /* We encounter a tree node with at least one unexpanded child.
691
                 * Expand it. By the time we hit this node again, the result of
692
                 * that child (and all earlier children) will be at the end of `results`. */
693
1.98M
                size_t child_index = stack.back().expanded++;
694
1.98M
                State child_state = downfn(stack.back().state, node, child_index);
695
1.98M
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
696
1.98M
                continue;
697
1.98M
            }
698
            // Invoke upfn with the last node.subs.size() elements of results as input.
699
3.97M
            assert(results.size() >= node.subs.size());
700
1.98M
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
701
1.98M
                std::span<Result>{results}.last(node.subs.size()))};
702
            // If evaluation returns std::nullopt, abort immediately.
703
1.98M
            if (!result) return {};
704
            // Replace the last node.subs.size() elements of results with the new result.
705
1.98M
            results.erase(results.end() - node.subs.size(), results.end());
706
1.98M
            results.push_back(std::move(*result));
707
1.98M
            stack.pop_back();
708
1.98M
        }
709
        // The final remaining results element is the root result, return it.
710
4.32k
        assert(results.size() >= 1);
711
4.32k
        CHECK_NONFATAL(results.size() == 1);
712
4.32k
        return std::move(results[0]);
713
4.32k
    }
std::optional<TapSatisfier> miniscript::Node<XOnlyPubKey>::TreeEvalMaybe<miniscript::internal::InputResult, TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::'lambda'(TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<XOnlyPubKey> const&, unsigned long), TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::'lambda'(TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>), TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::'lambda'(TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<XOnlyPubKey> const&, unsigned long), TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::'lambda'(TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const
Line
Count
Source
653
4.32k
    {
654
        /** Entries of the explicit stack tracked in this algorithm. */
655
4.32k
        struct StackElem
656
4.32k
        {
657
4.32k
            const Node& node; //!< The node being evaluated.
658
4.32k
            size_t expanded; //!< How many children of this node have been expanded.
659
4.32k
            State state; //!< The state for that node.
660
661
4.32k
            StackElem(const Node& node_, size_t exp_, State&& state_) :
662
4.32k
                node(node_), expanded(exp_), state(std::move(state_)) {}
663
4.32k
        };
664
        /* Stack of tree nodes being explored. */
665
4.32k
        std::vector<StackElem> stack;
666
        /* Results of subtrees so far. Their order and mapping to tree nodes
667
         * is implicitly defined by stack. */
668
4.32k
        std::vector<Result> results;
669
4.32k
        stack.emplace_back(*this, 0, std::move(root_state));
670
671
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
672
         * State variables are omitted for simplicity.
673
         *
674
         * First: stack=[(A,0)] results=[]
675
         *        stack=[(A,1),(B,0)] results=[]
676
         *        stack=[(A,1)] results=[B]
677
         *        stack=[(A,2),(C,0)] results=[B]
678
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
679
         *        stack=[(A,2),(C,1)] results=[B,D]
680
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
681
         *        stack=[(A,2),(C,2)] results=[B,D,E]
682
         *        stack=[(A,2)] results=[B,C]
683
         *        stack=[(A,3),(F,0)] results=[B,C]
684
         *        stack=[(A,3)] results=[B,C,F]
685
         * Final: stack=[] results=[A]
686
         */
687
3.97M
        while (stack.size()) {
688
3.97M
            const Node& node = stack.back().node;
689
3.97M
            if (stack.back().expanded < node.subs.size()) {
690
                /* We encounter a tree node with at least one unexpanded child.
691
                 * Expand it. By the time we hit this node again, the result of
692
                 * that child (and all earlier children) will be at the end of `results`. */
693
1.98M
                size_t child_index = stack.back().expanded++;
694
1.98M
                State child_state = downfn(stack.back().state, node, child_index);
695
1.98M
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
696
1.98M
                continue;
697
1.98M
            }
698
            // Invoke upfn with the last node.subs.size() elements of results as input.
699
3.97M
            assert(results.size() >= node.subs.size());
700
1.98M
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
701
1.98M
                std::span<Result>{results}.last(node.subs.size()))};
702
            // If evaluation returns std::nullopt, abort immediately.
703
1.98M
            if (!result) return {};
704
            // Replace the last node.subs.size() elements of results with the new result.
705
1.98M
            results.erase(results.end() - node.subs.size(), results.end());
706
1.98M
            results.push_back(std::move(*result));
707
1.98M
            stack.pop_back();
708
1.98M
        }
709
        // The final remaining results element is the root result, return it.
710
4.32k
        assert(results.size() >= 1);
711
4.32k
        CHECK_NONFATAL(results.size() == 1);
712
4.32k
        return std::move(results[0]);
713
4.32k
    }
std::optional<WshSatisfier> miniscript::Node<CPubKey>::TreeEvalMaybe<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, WshSatisfier miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::DummyState, WshSatisfier miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::'lambda'(WshSatisfier miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long), WshSatisfier miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::'lambda'(WshSatisfier miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>), WshSatisfier miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::'lambda'(WshSatisfier miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long), WshSatisfier miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::'lambda'(WshSatisfier miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const
Line
Count
Source
653
215
    {
654
        /** Entries of the explicit stack tracked in this algorithm. */
655
215
        struct StackElem
656
215
        {
657
215
            const Node& node; //!< The node being evaluated.
658
215
            size_t expanded; //!< How many children of this node have been expanded.
659
215
            State state; //!< The state for that node.
660
661
215
            StackElem(const Node& node_, size_t exp_, State&& state_) :
662
215
                node(node_), expanded(exp_), state(std::move(state_)) {}
663
215
        };
664
        /* Stack of tree nodes being explored. */
665
215
        std::vector<StackElem> stack;
666
        /* Results of subtrees so far. Their order and mapping to tree nodes
667
         * is implicitly defined by stack. */
668
215
        std::vector<Result> results;
669
215
        stack.emplace_back(*this, 0, std::move(root_state));
670
671
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
672
         * State variables are omitted for simplicity.
673
         *
674
         * First: stack=[(A,0)] results=[]
675
         *        stack=[(A,1),(B,0)] results=[]
676
         *        stack=[(A,1)] results=[B]
677
         *        stack=[(A,2),(C,0)] results=[B]
678
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
679
         *        stack=[(A,2),(C,1)] results=[B,D]
680
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
681
         *        stack=[(A,2),(C,2)] results=[B,D,E]
682
         *        stack=[(A,2)] results=[B,C]
683
         *        stack=[(A,3),(F,0)] results=[B,C]
684
         *        stack=[(A,3)] results=[B,C,F]
685
         * Final: stack=[] results=[A]
686
         */
687
6.26k
        while (stack.size()) {
688
6.05k
            const Node& node = stack.back().node;
689
6.05k
            if (stack.back().expanded < node.subs.size()) {
690
                /* We encounter a tree node with at least one unexpanded child.
691
                 * Expand it. By the time we hit this node again, the result of
692
                 * that child (and all earlier children) will be at the end of `results`. */
693
2.91k
                size_t child_index = stack.back().expanded++;
694
2.91k
                State child_state = downfn(stack.back().state, node, child_index);
695
2.91k
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
696
2.91k
                continue;
697
2.91k
            }
698
            // Invoke upfn with the last node.subs.size() elements of results as input.
699
6.05k
            assert(results.size() >= node.subs.size());
700
3.13k
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
701
3.13k
                std::span<Result>{results}.last(node.subs.size()))};
702
            // If evaluation returns std::nullopt, abort immediately.
703
3.13k
            if (!result) return {};
704
            // Replace the last node.subs.size() elements of results with the new result.
705
3.13k
            results.erase(results.end() - node.subs.size(), results.end());
706
3.13k
            results.push_back(std::move(*result));
707
3.13k
            stack.pop_back();
708
3.13k
        }
709
        // The final remaining results element is the root result, return it.
710
215
        assert(results.size() >= 1);
711
215
        CHECK_NONFATAL(results.size() == 1);
712
215
        return std::move(results[0]);
713
215
    }
std::optional<WshSatisfier> miniscript::Node<CPubKey>::TreeEvalMaybe<miniscript::internal::InputResult, WshSatisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, WshSatisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::'lambda'(WshSatisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long), WshSatisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::'lambda'(WshSatisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>), WshSatisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::'lambda'(WshSatisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long), WshSatisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::'lambda'(WshSatisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const
Line
Count
Source
653
215
    {
654
        /** Entries of the explicit stack tracked in this algorithm. */
655
215
        struct StackElem
656
215
        {
657
215
            const Node& node; //!< The node being evaluated.
658
215
            size_t expanded; //!< How many children of this node have been expanded.
659
215
            State state; //!< The state for that node.
660
661
215
            StackElem(const Node& node_, size_t exp_, State&& state_) :
662
215
                node(node_), expanded(exp_), state(std::move(state_)) {}
663
215
        };
664
        /* Stack of tree nodes being explored. */
665
215
        std::vector<StackElem> stack;
666
        /* Results of subtrees so far. Their order and mapping to tree nodes
667
         * is implicitly defined by stack. */
668
215
        std::vector<Result> results;
669
215
        stack.emplace_back(*this, 0, std::move(root_state));
670
671
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
672
         * State variables are omitted for simplicity.
673
         *
674
         * First: stack=[(A,0)] results=[]
675
         *        stack=[(A,1),(B,0)] results=[]
676
         *        stack=[(A,1)] results=[B]
677
         *        stack=[(A,2),(C,0)] results=[B]
678
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
679
         *        stack=[(A,2),(C,1)] results=[B,D]
680
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
681
         *        stack=[(A,2),(C,2)] results=[B,D,E]
682
         *        stack=[(A,2)] results=[B,C]
683
         *        stack=[(A,3),(F,0)] results=[B,C]
684
         *        stack=[(A,3)] results=[B,C,F]
685
         * Final: stack=[] results=[A]
686
         */
687
6.26k
        while (stack.size()) {
688
6.05k
            const Node& node = stack.back().node;
689
6.05k
            if (stack.back().expanded < node.subs.size()) {
690
                /* We encounter a tree node with at least one unexpanded child.
691
                 * Expand it. By the time we hit this node again, the result of
692
                 * that child (and all earlier children) will be at the end of `results`. */
693
2.91k
                size_t child_index = stack.back().expanded++;
694
2.91k
                State child_state = downfn(stack.back().state, node, child_index);
695
2.91k
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
696
2.91k
                continue;
697
2.91k
            }
698
            // Invoke upfn with the last node.subs.size() elements of results as input.
699
6.05k
            assert(results.size() >= node.subs.size());
700
3.13k
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
701
3.13k
                std::span<Result>{results}.last(node.subs.size()))};
702
            // If evaluation returns std::nullopt, abort immediately.
703
3.13k
            if (!result) return {};
704
            // Replace the last node.subs.size() elements of results with the new result.
705
3.13k
            results.erase(results.end() - node.subs.size(), results.end());
706
3.13k
            results.push_back(std::move(*result));
707
3.13k
            stack.pop_back();
708
3.13k
        }
709
        // The final remaining results element is the root result, return it.
710
215
        assert(results.size() >= 1);
711
215
        CHECK_NONFATAL(results.size() == 1);
712
215
        return std::move(results[0]);
713
215
    }
714
715
    /** Like TreeEvalMaybe, but without downfn or State type.
716
     * upfn takes (const Node&, std::span<Result>) and returns std::optional<Result>. */
717
    template<typename Result, typename UpFn>
718
    std::optional<Result> TreeEvalMaybe(UpFn upfn) const
719
    {
720
        struct DummyState {};
721
        return TreeEvalMaybe<Result>(DummyState{},
722
            [](DummyState, const Node&, size_t) { return DummyState{}; },
723
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
724
                return upfn(node, subs);
725
            }
726
        );
727
    }
728
729
    /** Like TreeEvalMaybe, but always produces a result. upfn must return Result. */
730
    template<typename Result, typename State, typename DownFn, typename UpFn>
731
    Result TreeEval(State root_state, DownFn&& downfn, UpFn upfn) const
732
1.88k
    {
733
        // Invoke TreeEvalMaybe with upfn wrapped to return std::optional<Result>, and then
734
        // unconditionally dereference the result (it cannot be std::nullopt).
735
1.88k
        return std::move(*TreeEvalMaybe<Result>(std::move(root_state),
736
1.88k
            std::forward<DownFn>(downfn),
737
1.68M
            [&upfn](State&& state, const Node& node, std::span<Result> subs) {
738
1.68M
                Result res{upfn(std::move(state), node, subs)};
739
1.68M
                return std::optional<Result>(std::move(res));
740
1.68M
            }
miniscript_tests.cpp:(anonymous namespace)::KeyConverter miniscript::Node<CPubKey>::TreeEval<CScript, bool, CScript miniscript::Node<CPubKey>::ToScript<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, unsigned long)&, CScript miniscript::Node<CPubKey>::ToScript<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, std::span<CScript, 18446744073709551615ul>)>(bool, CScript miniscript::Node<CPubKey>::ToScript<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, unsigned long)&, CScript miniscript::Node<CPubKey>::ToScript<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, std::span<CScript, 18446744073709551615ul>)) const::'lambda'(bool&&, miniscript::Node<CPubKey> const&, std::span<CScript, 18446744073709551615ul>)::operator()(bool&&, miniscript::Node<CPubKey> const&, std::span<CScript, 18446744073709551615ul>) const
Line
Count
Source
737
25.4k
            [&upfn](State&& state, const Node& node, std::span<Result> subs) {
738
25.4k
                Result res{upfn(std::move(state), node, subs)};
739
25.4k
                return std::optional<Result>(std::move(res));
740
25.4k
            }
descriptor.cpp:(anonymous namespace)::ScriptMaker miniscript::Node<unsigned int>::TreeEval<CScript, bool, CScript miniscript::Node<unsigned int>::ToScript<(anonymous namespace)::ScriptMaker>((anonymous namespace)::ScriptMaker const&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, unsigned long)&, CScript miniscript::Node<unsigned int>::ToScript<(anonymous namespace)::ScriptMaker>((anonymous namespace)::ScriptMaker const&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, std::span<CScript, 18446744073709551615ul>)>(bool, CScript miniscript::Node<unsigned int>::ToScript<(anonymous namespace)::ScriptMaker>((anonymous namespace)::ScriptMaker const&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, unsigned long)&, CScript miniscript::Node<unsigned int>::ToScript<(anonymous namespace)::ScriptMaker>((anonymous namespace)::ScriptMaker const&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, std::span<CScript, 18446744073709551615ul>)) const::'lambda'(bool&&, miniscript::Node<unsigned int> const&, std::span<CScript, 18446744073709551615ul>)::operator()(bool&&, miniscript::Node<unsigned int> const&, std::span<CScript, 18446744073709551615ul>) const
Line
Count
Source
737
1.66M
            [&upfn](State&& state, const Node& node, std::span<Result> subs) {
738
1.66M
                Result res{upfn(std::move(state), node, subs)};
739
1.66M
                return std::optional<Result>(std::move(res));
740
1.66M
            }
741
1.88k
        ));
742
1.88k
    }
miniscript_tests.cpp:(anonymous namespace)::KeyConverter miniscript::Node<CPubKey>::TreeEval<CScript, bool, CScript miniscript::Node<CPubKey>::ToScript<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, unsigned long)&, CScript miniscript::Node<CPubKey>::ToScript<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, std::span<CScript, 18446744073709551615ul>)>(bool, CScript miniscript::Node<CPubKey>::ToScript<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, unsigned long)&, CScript miniscript::Node<CPubKey>::ToScript<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, std::span<CScript, 18446744073709551615ul>)) const
Line
Count
Source
732
375
    {
733
        // Invoke TreeEvalMaybe with upfn wrapped to return std::optional<Result>, and then
734
        // unconditionally dereference the result (it cannot be std::nullopt).
735
375
        return std::move(*TreeEvalMaybe<Result>(std::move(root_state),
736
375
            std::forward<DownFn>(downfn),
737
375
            [&upfn](State&& state, const Node& node, std::span<Result> subs) {
738
375
                Result res{upfn(std::move(state), node, subs)};
739
375
                return std::optional<Result>(std::move(res));
740
375
            }
741
375
        ));
742
375
    }
descriptor.cpp:(anonymous namespace)::ScriptMaker miniscript::Node<unsigned int>::TreeEval<CScript, bool, CScript miniscript::Node<unsigned int>::ToScript<(anonymous namespace)::ScriptMaker>((anonymous namespace)::ScriptMaker const&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, unsigned long)&, CScript miniscript::Node<unsigned int>::ToScript<(anonymous namespace)::ScriptMaker>((anonymous namespace)::ScriptMaker const&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, std::span<CScript, 18446744073709551615ul>)>(bool, CScript miniscript::Node<unsigned int>::ToScript<(anonymous namespace)::ScriptMaker>((anonymous namespace)::ScriptMaker const&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, unsigned long)&, CScript miniscript::Node<unsigned int>::ToScript<(anonymous namespace)::ScriptMaker>((anonymous namespace)::ScriptMaker const&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, std::span<CScript, 18446744073709551615ul>)) const
Line
Count
Source
732
1.50k
    {
733
        // Invoke TreeEvalMaybe with upfn wrapped to return std::optional<Result>, and then
734
        // unconditionally dereference the result (it cannot be std::nullopt).
735
1.50k
        return std::move(*TreeEvalMaybe<Result>(std::move(root_state),
736
1.50k
            std::forward<DownFn>(downfn),
737
1.50k
            [&upfn](State&& state, const Node& node, std::span<Result> subs) {
738
1.50k
                Result res{upfn(std::move(state), node, subs)};
739
1.50k
                return std::optional<Result>(std::move(res));
740
1.50k
            }
741
1.50k
        ));
742
1.50k
    }
743
744
    /** Like TreeEval, but without downfn or State type.
745
     *  upfn takes (const Node&, std::span<Result>) and returns Result. */
746
    template<typename Result, typename UpFn>
747
    Result TreeEval(UpFn upfn) const
748
15.5k
    {
749
15.5k
        struct DummyState {};
750
15.5k
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
751
7.15M
            [](DummyState, const Node&, size_t) { return DummyState{}; },
miniscript_tests.cpp:(anonymous namespace)::Satisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::Satisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long)::operator()((anonymous namespace)::Satisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long) const
Line
Count
Source
751
1.61M
            [](DummyState, const Node&, size_t) { return DummyState{}; },
miniscript_tests.cpp:(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&) miniscript::Node<CPubKey>::TreeEval<int, bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)>(bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&) miniscript::Node<CPubKey>::TreeEval<int, bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)>(bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long)::operator()((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&) miniscript::Node<CPubKey>::TreeEval<int, bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)>(bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long) const
Line
Count
Source
751
25.0k
            [](DummyState, const Node&, size_t) { return DummyState{}; },
miniscript_tests.cpp:(anonymous namespace)::KeyConverter miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::KeyConverter miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long)::operator()((anonymous namespace)::KeyConverter miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long) const
Line
Count
Source
751
22.9k
            [](DummyState, const Node&, size_t) { return DummyState{}; },
miniscript::Node<CPubKey> const* miniscript::Node<CPubKey>::TreeEval<miniscript::Node<CPubKey> const*, miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)>(miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)) const::'lambda'(miniscript::Node<CPubKey> const* miniscript::Node<CPubKey>::TreeEval<miniscript::Node<CPubKey> const*, miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)>(miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long)::operator()(miniscript::Node<CPubKey> const* miniscript::Node<CPubKey>::TreeEval<miniscript::Node<CPubKey> const*, miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)>(miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long) const
Line
Count
Source
751
6
            [](DummyState, const Node&, size_t) { return DummyState{}; },
miniscript::Node<unsigned int> miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int>, miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)) const::'lambda'(miniscript::Node<unsigned int> miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int>, miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, unsigned long)::operator()(miniscript::Node<unsigned int> miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int>, miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, unsigned long) const
Line
Count
Source
751
530k
            [](DummyState, const Node&, size_t) { return DummyState{}; },
descriptor.cpp:(anonymous namespace)::KeyParser miniscript::Node<unsigned int>::TreeEval<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)>(void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::KeyParser miniscript::Node<unsigned int>::TreeEval<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)>(void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, unsigned long)::operator()((anonymous namespace)::KeyParser miniscript::Node<unsigned int>::TreeEval<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)>(void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, unsigned long) const
Line
Count
Source
751
994k
            [](DummyState, const Node&, size_t) { return DummyState{}; },
miniscript::Node<unsigned int> const* miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int> const*, miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)) const::'lambda'(miniscript::Node<unsigned int> const* miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int> const*, miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, unsigned long)::operator()(miniscript::Node<unsigned int> const* miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int> const*, miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, unsigned long) const
Line
Count
Source
751
93
            [](DummyState, const Node&, size_t) { return DummyState{}; },
TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)) const::'lambda'(TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<XOnlyPubKey> const&, unsigned long)::operator()(TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<XOnlyPubKey> const&, unsigned long) const
Line
Count
Source
751
1.98M
            [](DummyState, const Node&, size_t) { return DummyState{}; },
TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::'lambda'(TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<XOnlyPubKey> const&, unsigned long)::operator()(TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<XOnlyPubKey> const&, unsigned long) const
Line
Count
Source
751
1.98M
            [](DummyState, const Node&, size_t) { return DummyState{}; },
WshSatisfier miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::'lambda'(WshSatisfier miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long)::operator()(WshSatisfier miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long) const
Line
Count
Source
751
2.91k
            [](DummyState, const Node&, size_t) { return DummyState{}; },
WshSatisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::'lambda'(WshSatisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long)::operator()(WshSatisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, unsigned long) const
Line
Count
Source
751
2.91k
            [](DummyState, const Node&, size_t) { return DummyState{}; },
752
7.17M
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
753
7.17M
                Result res{upfn(node, subs)};
754
7.17M
                return std::optional<Result>(std::move(res));
755
7.17M
            }
miniscript_tests.cpp:(anonymous namespace)::Satisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::Satisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)::operator()((anonymous namespace)::Satisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>) const
Line
Count
Source
752
1.61M
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
753
1.61M
                Result res{upfn(node, subs)};
754
1.61M
                return std::optional<Result>(std::move(res));
755
1.61M
            }
miniscript_tests.cpp:(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&) miniscript::Node<CPubKey>::TreeEval<int, bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)>(bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&) miniscript::Node<CPubKey>::TreeEval<int, bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)>(bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)::operator()((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&) miniscript::Node<CPubKey>::TreeEval<int, bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)>(bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>) const
Line
Count
Source
752
25.4k
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
753
25.4k
                Result res{upfn(node, subs)};
754
25.4k
                return std::optional<Result>(std::move(res));
755
25.4k
            }
miniscript_tests.cpp:(anonymous namespace)::KeyConverter miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::KeyConverter miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)::operator()((anonymous namespace)::KeyConverter miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>) const
Line
Count
Source
752
23.2k
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
753
23.2k
                Result res{upfn(node, subs)};
754
23.2k
                return std::optional<Result>(std::move(res));
755
23.2k
            }
miniscript::Node<CPubKey> const* miniscript::Node<CPubKey>::TreeEval<miniscript::Node<CPubKey> const*, miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)>(miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)) const::'lambda'(miniscript::Node<CPubKey> const* miniscript::Node<CPubKey>::TreeEval<miniscript::Node<CPubKey> const*, miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)>(miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)::operator()(miniscript::Node<CPubKey> const* miniscript::Node<CPubKey>::TreeEval<miniscript::Node<CPubKey> const*, miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)>(miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>) const
Line
Count
Source
752
7
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
753
7
                Result res{upfn(node, subs)};
754
7
                return std::optional<Result>(std::move(res));
755
7
            }
miniscript::Node<unsigned int> miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int>, miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)) const::'lambda'(miniscript::Node<unsigned int> miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int>, miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)::operator()(miniscript::Node<unsigned int> miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int>, miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>) const
Line
Count
Source
752
531k
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
753
531k
                Result res{upfn(node, subs)};
754
531k
                return std::optional<Result>(std::move(res));
755
531k
            }
descriptor.cpp:(anonymous namespace)::KeyParser miniscript::Node<unsigned int>::TreeEval<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)>(void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)) const::'lambda'((anonymous namespace)::KeyParser miniscript::Node<unsigned int>::TreeEval<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)>(void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)::operator()((anonymous namespace)::KeyParser miniscript::Node<unsigned int>::TreeEval<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)>(void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>) const
Line
Count
Source
752
995k
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
753
995k
                Result res{upfn(node, subs)};
754
995k
                return std::optional<Result>(std::move(res));
755
995k
            }
miniscript::Node<unsigned int> const* miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int> const*, miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)) const::'lambda'(miniscript::Node<unsigned int> const* miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int> const*, miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)::operator()(miniscript::Node<unsigned int> const* miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int> const*, miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)) const::DummyState, miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>) const
Line
Count
Source
752
107
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
753
107
                Result res{upfn(node, subs)};
754
107
                return std::optional<Result>(std::move(res));
755
107
            }
TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)) const::'lambda'(TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)::operator()(TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>) const
Line
Count
Source
752
1.98M
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
753
1.98M
                Result res{upfn(node, subs)};
754
1.98M
                return std::optional<Result>(std::move(res));
755
1.98M
            }
TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::'lambda'(TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)::operator()(TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>) const
Line
Count
Source
752
1.98M
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
753
1.98M
                Result res{upfn(node, subs)};
754
1.98M
                return std::optional<Result>(std::move(res));
755
1.98M
            }
WshSatisfier miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::'lambda'(WshSatisfier miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)::operator()(WshSatisfier miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>) const
Line
Count
Source
752
3.13k
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
753
3.13k
                Result res{upfn(node, subs)};
754
3.13k
                return std::optional<Result>(std::move(res));
755
3.13k
            }
WshSatisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::'lambda'(WshSatisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)::operator()(WshSatisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const::DummyState, miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>) const
Line
Count
Source
752
3.13k
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
753
3.13k
                Result res{upfn(node, subs)};
754
3.13k
                return std::optional<Result>(std::move(res));
755
3.13k
            }
756
15.5k
        ));
757
15.5k
    }
miniscript_tests.cpp:(anonymous namespace)::Satisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const
Line
Count
Source
748
4.82k
    {
749
4.82k
        struct DummyState {};
750
4.82k
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
751
4.82k
            [](DummyState, const Node&, size_t) { return DummyState{}; },
752
4.82k
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
753
4.82k
                Result res{upfn(node, subs)};
754
4.82k
                return std::optional<Result>(std::move(res));
755
4.82k
            }
756
4.82k
        ));
757
4.82k
    }
miniscript_tests.cpp:(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&) miniscript::Node<CPubKey>::TreeEval<int, bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)>(bool miniscript::Node<CPubKey>::IsSatisfiable<(anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)>((anonymous namespace)::MiniScriptTest::TestSatisfy((anonymous namespace)::KeyConverter const&, miniscript::Node<CPubKey> const&)::'lambda'(miniscript::Node<CPubKey> const&)) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<int, 18446744073709551615ul>)) const
Line
Count
Source
748
375
    {
749
375
        struct DummyState {};
750
375
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
751
375
            [](DummyState, const Node&, size_t) { return DummyState{}; },
752
375
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
753
375
                Result res{upfn(node, subs)};
754
375
                return std::optional<Result>(std::move(res));
755
375
            }
756
375
        ));
757
375
    }
miniscript_tests.cpp:(anonymous namespace)::KeyConverter miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const
Line
Count
Source
748
313
    {
749
313
        struct DummyState {};
750
313
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
751
313
            [](DummyState, const Node&, size_t) { return DummyState{}; },
752
313
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
753
313
                Result res{upfn(node, subs)};
754
313
                return std::optional<Result>(std::move(res));
755
313
            }
756
313
        ));
757
313
    }
miniscript::Node<CPubKey> const* miniscript::Node<CPubKey>::TreeEval<miniscript::Node<CPubKey> const*, miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)>(miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)) const
Line
Count
Source
748
1
    {
749
1
        struct DummyState {};
750
1
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
751
1
            [](DummyState, const Node&, size_t) { return DummyState{}; },
752
1
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
753
1
                Result res{upfn(node, subs)};
754
1
                return std::optional<Result>(std::move(res));
755
1
            }
756
1
        ));
757
1
    }
miniscript::Node<unsigned int> miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int>, miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::Clone() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int>, 18446744073709551615ul>)) const
Line
Count
Source
748
193
    {
749
193
        struct DummyState {};
750
193
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
751
193
            [](DummyState, const Node&, size_t) { return DummyState{}; },
752
193
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
753
193
                Result res{upfn(node, subs)};
754
193
                return std::optional<Result>(std::move(res));
755
193
            }
756
193
        ));
757
193
    }
descriptor.cpp:(anonymous namespace)::KeyParser miniscript::Node<unsigned int>::TreeEval<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)>(void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)) const
Line
Count
Source
748
788
    {
749
788
        struct DummyState {};
750
788
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
751
788
            [](DummyState, const Node&, size_t) { return DummyState{}; },
752
788
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
753
788
                Result res{upfn(node, subs)};
754
788
                return std::optional<Result>(std::move(res));
755
788
            }
756
788
        ));
757
788
    }
miniscript::Node<unsigned int> const* miniscript::Node<unsigned int>::TreeEval<miniscript::Node<unsigned int> const*, miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)>(miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)) const
Line
Count
Source
748
14
    {
749
14
        struct DummyState {};
750
14
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
751
14
            [](DummyState, const Node&, size_t) { return DummyState{}; },
752
14
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
753
14
                Result res{upfn(node, subs)};
754
14
                return std::optional<Result>(std::move(res));
755
14
            }
756
14
        ));
757
14
    }
TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)) const
Line
Count
Source
748
4.32k
    {
749
4.32k
        struct DummyState {};
750
4.32k
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
751
4.32k
            [](DummyState, const Node&, size_t) { return DummyState{}; },
752
4.32k
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
753
4.32k
                Result res{upfn(node, subs)};
754
4.32k
                return std::optional<Result>(std::move(res));
755
4.32k
            }
756
4.32k
        ));
757
4.32k
    }
TapSatisfier miniscript::Node<XOnlyPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const
Line
Count
Source
748
4.32k
    {
749
4.32k
        struct DummyState {};
750
4.32k
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
751
4.32k
            [](DummyState, const Node&, size_t) { return DummyState{}; },
752
4.32k
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
753
4.32k
                Result res{upfn(node, subs)};
754
4.32k
                return std::optional<Result>(std::move(res));
755
4.32k
            }
756
4.32k
        ));
757
4.32k
    }
WshSatisfier miniscript::Node<CPubKey>::TreeEval<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)>(void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)) const
Line
Count
Source
748
215
    {
749
215
        struct DummyState {};
750
215
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
751
215
            [](DummyState, const Node&, size_t) { return DummyState{}; },
752
215
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
753
215
                Result res{upfn(node, subs)};
754
215
                return std::optional<Result>(std::move(res));
755
215
            }
756
215
        ));
757
215
    }
WshSatisfier miniscript::Node<CPubKey>::TreeEval<miniscript::internal::InputResult, miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)>(miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)) const
Line
Count
Source
748
215
    {
749
215
        struct DummyState {};
750
215
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
751
215
            [](DummyState, const Node&, size_t) { return DummyState{}; },
752
215
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
753
215
                Result res{upfn(node, subs)};
754
215
                return std::optional<Result>(std::move(res));
755
215
            }
756
215
        ));
757
215
    }
758
759
    /** Compare two miniscript subtrees, using a non-recursive algorithm. */
760
    friend int Compare(const Node<Key>& node1, const Node<Key>& node2)
761
    {
762
        std::vector<std::pair<const Node<Key>&, const Node<Key>&>> queue;
763
        queue.emplace_back(node1, node2);
764
        while (!queue.empty()) {
765
            const auto& [a, b] = queue.back();
766
            queue.pop_back();
767
            if (std::tie(a.fragment, a.k, a.keys, a.data) < std::tie(b.fragment, b.k, b.keys, b.data)) return -1;
768
            if (std::tie(b.fragment, b.k, b.keys, b.data) < std::tie(a.fragment, a.k, a.keys, a.data)) return 1;
769
            if (a.subs.size() < b.subs.size()) return -1;
770
            if (b.subs.size() < a.subs.size()) return 1;
771
            size_t n = a.subs.size();
772
            for (size_t i = 0; i < n; ++i) {
773
                queue.emplace_back(a.subs[n - 1 - i], b.subs[n - 1 - i]);
774
            }
775
        }
776
        return 0;
777
    }
778
779
    //! Compute the type for this miniscript.
780
3.74M
    Type CalcType() const {
781
3.74M
        using namespace internal;
782
783
        // THRESH has a variable number of subexpressions
784
3.74M
        std::vector<Type> sub_types;
785
3.74M
        if (fragment == Fragment::THRESH) {
786
1.58k
            for (const auto& sub : subs) sub_types.push_back(sub.GetType());
787
411
        }
788
        // All other nodes than THRESH can be computed just from the types of the 0-3 subexpressions.
789
3.74M
        Type x = subs.size() > 0 ? subs[0].GetType() : ""_mst;
790
3.74M
        Type y = subs.size() > 1 ? subs[1].GetType() : ""_mst;
791
3.74M
        Type z = subs.size() > 2 ? subs[2].GetType() : ""_mst;
792
793
3.74M
        return SanitizeType(ComputeType(fragment, x, y, z, sub_types, k, data.size(), subs.size(), keys.size(), m_script_ctx));
794
3.74M
    }
miniscript::Node<CPubKey>::CalcType() const
Line
Count
Source
780
28.4k
    Type CalcType() const {
781
28.4k
        using namespace internal;
782
783
        // THRESH has a variable number of subexpressions
784
28.4k
        std::vector<Type> sub_types;
785
28.4k
        if (fragment == Fragment::THRESH) {
786
700
            for (const auto& sub : subs) sub_types.push_back(sub.GetType());
787
147
        }
788
        // All other nodes than THRESH can be computed just from the types of the 0-3 subexpressions.
789
28.4k
        Type x = subs.size() > 0 ? subs[0].GetType() : ""_mst;
790
28.4k
        Type y = subs.size() > 1 ? subs[1].GetType() : ""_mst;
791
28.4k
        Type z = subs.size() > 2 ? subs[2].GetType() : ""_mst;
792
793
28.4k
        return SanitizeType(ComputeType(fragment, x, y, z, sub_types, k, data.size(), subs.size(), keys.size(), m_script_ctx));
794
28.4k
    }
miniscript::Node<unsigned int>::CalcType() const
Line
Count
Source
780
1.72M
    Type CalcType() const {
781
1.72M
        using namespace internal;
782
783
        // THRESH has a variable number of subexpressions
784
1.72M
        std::vector<Type> sub_types;
785
1.72M
        if (fragment == Fragment::THRESH) {
786
814
            for (const auto& sub : subs) sub_types.push_back(sub.GetType());
787
242
        }
788
        // All other nodes than THRESH can be computed just from the types of the 0-3 subexpressions.
789
1.72M
        Type x = subs.size() > 0 ? subs[0].GetType() : ""_mst;
790
1.72M
        Type y = subs.size() > 1 ? subs[1].GetType() : ""_mst;
791
1.72M
        Type z = subs.size() > 2 ? subs[2].GetType() : ""_mst;
792
793
1.72M
        return SanitizeType(ComputeType(fragment, x, y, z, sub_types, k, data.size(), subs.size(), keys.size(), m_script_ctx));
794
1.72M
    }
miniscript::Node<XOnlyPubKey>::CalcType() const
Line
Count
Source
780
1.98M
    Type CalcType() const {
781
1.98M
        using namespace internal;
782
783
        // THRESH has a variable number of subexpressions
784
1.98M
        std::vector<Type> sub_types;
785
1.98M
        if (fragment == Fragment::THRESH) {
786
66
            for (const auto& sub : subs) sub_types.push_back(sub.GetType());
787
22
        }
788
        // All other nodes than THRESH can be computed just from the types of the 0-3 subexpressions.
789
1.98M
        Type x = subs.size() > 0 ? subs[0].GetType() : ""_mst;
790
1.98M
        Type y = subs.size() > 1 ? subs[1].GetType() : ""_mst;
791
1.98M
        Type z = subs.size() > 2 ? subs[2].GetType() : ""_mst;
792
793
1.98M
        return SanitizeType(ComputeType(fragment, x, y, z, sub_types, k, data.size(), subs.size(), keys.size(), m_script_ctx));
794
1.98M
    }
795
796
public:
797
    template<typename Ctx>
798
    CScript ToScript(const Ctx& ctx) const
799
1.88k
    {
800
        // To construct the CScript for a Miniscript object, we use the TreeEval algorithm.
801
        // The State is a boolean: whether or not the node's script expansion is followed
802
        // by an OP_VERIFY (which may need to be combined with the last script opcode).
803
1.68M
        auto downfn = [](bool verify, const Node& node, size_t index) {
804
            // For WRAP_V, the subexpression is certainly followed by OP_VERIFY.
805
1.68M
            if (node.fragment == Fragment::WRAP_V) return true;
806
            // The subexpression of WRAP_S, and the last subexpression of AND_V
807
            // inherit the followed-by-OP_VERIFY property from the parent.
808
1.68M
            if (node.fragment == Fragment::WRAP_S ||
809
1.68M
                (node.fragment == Fragment::AND_V && index == 1)) return verify;
810
1.68M
            return false;
811
1.68M
        };
miniscript_tests.cpp:CScript miniscript::Node<CPubKey>::ToScript<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, unsigned long)::operator()(bool, miniscript::Node<CPubKey> const&, unsigned long) const
Line
Count
Source
803
25.0k
        auto downfn = [](bool verify, const Node& node, size_t index) {
804
            // For WRAP_V, the subexpression is certainly followed by OP_VERIFY.
805
25.0k
            if (node.fragment == Fragment::WRAP_V) return true;
806
            // The subexpression of WRAP_S, and the last subexpression of AND_V
807
            // inherit the followed-by-OP_VERIFY property from the parent.
808
24.7k
            if (node.fragment == Fragment::WRAP_S ||
809
24.7k
                (node.fragment == Fragment::AND_V && index == 1)) return verify;
810
24.5k
            return false;
811
24.7k
        };
descriptor.cpp:CScript miniscript::Node<unsigned int>::ToScript<(anonymous namespace)::ScriptMaker>((anonymous namespace)::ScriptMaker const&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, unsigned long)::operator()(bool, miniscript::Node<unsigned int> const&, unsigned long) const
Line
Count
Source
803
1.66M
        auto downfn = [](bool verify, const Node& node, size_t index) {
804
            // For WRAP_V, the subexpression is certainly followed by OP_VERIFY.
805
1.66M
            if (node.fragment == Fragment::WRAP_V) return true;
806
            // The subexpression of WRAP_S, and the last subexpression of AND_V
807
            // inherit the followed-by-OP_VERIFY property from the parent.
808
1.66M
            if (node.fragment == Fragment::WRAP_S ||
809
1.66M
                (node.fragment == Fragment::AND_V && index == 1)) return verify;
810
1.65M
            return false;
811
1.66M
        };
812
        // The upward function computes for a node, given its followed-by-OP_VERIFY status
813
        // and the CScripts of its child nodes, the CScript of the node.
814
1.88k
        const bool is_tapscript{IsTapscript(m_script_ctx)};
815
1.68M
        auto upfn = [&ctx, is_tapscript](bool verify, const Node& node, std::span<CScript> subs) -> CScript {
816
1.68M
            switch (node.fragment) {
817
3.70k
                case Fragment::PK_K: return BuildScript(ctx.ToPKBytes(node.keys[0]));
818
590
                case Fragment::PK_H: return BuildScript(OP_DUP, OP_HASH160, ctx.ToPKHBytes(node.keys[0]), OP_EQUALVERIFY);
819
6.53k
                case Fragment::OLDER: return BuildScript(node.k, OP_CHECKSEQUENCEVERIFY);
820
1.13k
                case Fragment::AFTER: return BuildScript(node.k, OP_CHECKLOCKTIMEVERIFY);
821
133
                case Fragment::SHA256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_SHA256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
822
113
                case Fragment::RIPEMD160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_RIPEMD160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
823
162
                case Fragment::HASH256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
824
117
                case Fragment::HASH160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
825
7.82k
                case Fragment::WRAP_A: return BuildScript(OP_TOALTSTACK, subs[0], OP_FROMALTSTACK);
826
1.52k
                case Fragment::WRAP_S: return BuildScript(OP_SWAP, subs[0]);
827
4.23k
                case Fragment::WRAP_C: return BuildScript(std::move(subs[0]), verify ? OP_CHECKSIGVERIFY : OP_CHECKSIG);
828
145
                case Fragment::WRAP_D: return BuildScript(OP_DUP, OP_IF, subs[0], OP_ENDIF);
829
1.28k
                case Fragment::WRAP_V: {
830
1.28k
                    if (node.subs[0].GetType() << "x"_mst) {
831
352
                        return BuildScript(std::move(subs[0]), OP_VERIFY);
832
935
                    } else {
833
935
                        return std::move(subs[0]);
834
935
                    }
835
1.28k
                }
836
24
                case Fragment::WRAP_J: return BuildScript(OP_SIZE, OP_0NOTEQUAL, OP_IF, subs[0], OP_ENDIF);
837
1.64M
                case Fragment::WRAP_N: return BuildScript(std::move(subs[0]), OP_0NOTEQUAL);
838
236
                case Fragment::JUST_1: return BuildScript(OP_1);
839
1.14k
                case Fragment::JUST_0: return BuildScript(OP_0);
840
1.11k
                case Fragment::AND_V: return BuildScript(std::move(subs[0]), subs[1]);
841
7.42k
                case Fragment::AND_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLAND);
842
113
                case Fragment::OR_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLOR);
843
150
                case Fragment::OR_D: return BuildScript(std::move(subs[0]), OP_IFDUP, OP_NOTIF, subs[1], OP_ENDIF);
844
57
                case Fragment::OR_C: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[1], OP_ENDIF);
845
1.05k
                case Fragment::OR_I: return BuildScript(OP_IF, subs[0], OP_ELSE, subs[1], OP_ENDIF);
846
262
                case Fragment::ANDOR: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[2], OP_ELSE, subs[1], OP_ENDIF);
847
212
                case Fragment::MULTI: {
848
212
                    CHECK_NONFATAL(!is_tapscript);
849
212
                    CScript script = BuildScript(node.k);
850
445
                    for (const auto& key : node.keys) {
851
445
                        script = BuildScript(std::move(script), ctx.ToPKBytes(key));
852
445
                    }
853
212
                    return BuildScript(std::move(script), node.keys.size(), verify ? OP_CHECKMULTISIGVERIFY : OP_CHECKMULTISIG);
854
1.28k
                }
855
52
                case Fragment::MULTI_A: {
856
52
                    CHECK_NONFATAL(is_tapscript);
857
52
                    CScript script = BuildScript(ctx.ToPKBytes(*node.keys.begin()), OP_CHECKSIG);
858
197
                    for (auto it = node.keys.begin() + 1; it != node.keys.end(); ++it) {
859
145
                        script = BuildScript(std::move(script), ctx.ToPKBytes(*it), OP_CHECKSIGADD);
860
145
                    }
861
52
                    return BuildScript(std::move(script), node.k, verify ? OP_NUMEQUALVERIFY : OP_NUMEQUAL);
862
1.28k
                }
863
548
                case Fragment::THRESH: {
864
548
                    CScript script = std::move(subs[0]);
865
2.35k
                    for (size_t i = 1; i < subs.size(); ++i) {
866
1.80k
                        script = BuildScript(std::move(script), subs[i], OP_ADD);
867
1.80k
                    }
868
548
                    return BuildScript(std::move(script), node.k, verify ? OP_EQUALVERIFY : OP_EQUAL);
869
1.28k
                }
870
1.68M
            }
871
1.68M
            assert(false);
872
0
        };
miniscript_tests.cpp:CScript miniscript::Node<CPubKey>::ToScript<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, std::span<CScript, 18446744073709551615ul>)::operator()(bool, miniscript::Node<CPubKey> const&, std::span<CScript, 18446744073709551615ul>) const
Line
Count
Source
815
25.4k
        auto upfn = [&ctx, is_tapscript](bool verify, const Node& node, std::span<CScript> subs) -> CScript {
816
25.4k
            switch (node.fragment) {
817
1.36k
                case Fragment::PK_K: return BuildScript(ctx.ToPKBytes(node.keys[0]));
818
78
                case Fragment::PK_H: return BuildScript(OP_DUP, OP_HASH160, ctx.ToPKHBytes(node.keys[0]), OP_EQUALVERIFY);
819
6.11k
                case Fragment::OLDER: return BuildScript(node.k, OP_CHECKSEQUENCEVERIFY);
820
195
                case Fragment::AFTER: return BuildScript(node.k, OP_CHECKLOCKTIMEVERIFY);
821
63
                case Fragment::SHA256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_SHA256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
822
21
                case Fragment::RIPEMD160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_RIPEMD160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
823
42
                case Fragment::HASH256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
824
18
                case Fragment::HASH160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
825
7.33k
                case Fragment::WRAP_A: return BuildScript(OP_TOALTSTACK, subs[0], OP_FROMALTSTACK);
826
30
                case Fragment::WRAP_S: return BuildScript(OP_SWAP, subs[0]);
827
1.39k
                case Fragment::WRAP_C: return BuildScript(std::move(subs[0]), verify ? OP_CHECKSIGVERIFY : OP_CHECKSIG);
828
15
                case Fragment::WRAP_D: return BuildScript(OP_DUP, OP_IF, subs[0], OP_ENDIF);
829
243
                case Fragment::WRAP_V: {
830
243
                    if (node.subs[0].GetType() << "x"_mst) {
831
192
                        return BuildScript(std::move(subs[0]), OP_VERIFY);
832
192
                    } else {
833
51
                        return std::move(subs[0]);
834
51
                    }
835
243
                }
836
24
                case Fragment::WRAP_J: return BuildScript(OP_SIZE, OP_0NOTEQUAL, OP_IF, subs[0], OP_ENDIF);
837
45
                case Fragment::WRAP_N: return BuildScript(std::move(subs[0]), OP_0NOTEQUAL);
838
231
                case Fragment::JUST_1: return BuildScript(OP_1);
839
249
                case Fragment::JUST_0: return BuildScript(OP_0);
840
198
                case Fragment::AND_V: return BuildScript(std::move(subs[0]), subs[1]);
841
7.25k
                case Fragment::AND_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLAND);
842
24
                case Fragment::OR_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLOR);
843
45
                case Fragment::OR_D: return BuildScript(std::move(subs[0]), OP_IFDUP, OP_NOTIF, subs[1], OP_ENDIF);
844
18
                case Fragment::OR_C: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[1], OP_ENDIF);
845
237
                case Fragment::OR_I: return BuildScript(OP_IF, subs[0], OP_ELSE, subs[1], OP_ENDIF);
846
87
                case Fragment::ANDOR: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[2], OP_ELSE, subs[1], OP_ENDIF);
847
36
                case Fragment::MULTI: {
848
36
                    CHECK_NONFATAL(!is_tapscript);
849
36
                    CScript script = BuildScript(node.k);
850
69
                    for (const auto& key : node.keys) {
851
69
                        script = BuildScript(std::move(script), ctx.ToPKBytes(key));
852
69
                    }
853
36
                    return BuildScript(std::move(script), node.keys.size(), verify ? OP_CHECKMULTISIGVERIFY : OP_CHECKMULTISIG);
854
243
                }
855
6
                case Fragment::MULTI_A: {
856
6
                    CHECK_NONFATAL(is_tapscript);
857
6
                    CScript script = BuildScript(ctx.ToPKBytes(*node.keys.begin()), OP_CHECKSIG);
858
69
                    for (auto it = node.keys.begin() + 1; it != node.keys.end(); ++it) {
859
63
                        script = BuildScript(std::move(script), ctx.ToPKBytes(*it), OP_CHECKSIGADD);
860
63
                    }
861
6
                    return BuildScript(std::move(script), node.k, verify ? OP_NUMEQUALVERIFY : OP_NUMEQUAL);
862
243
                }
863
48
                case Fragment::THRESH: {
864
48
                    CScript script = std::move(subs[0]);
865
138
                    for (size_t i = 1; i < subs.size(); ++i) {
866
90
                        script = BuildScript(std::move(script), subs[i], OP_ADD);
867
90
                    }
868
48
                    return BuildScript(std::move(script), node.k, verify ? OP_EQUALVERIFY : OP_EQUAL);
869
243
                }
870
25.4k
            }
871
25.4k
            assert(false);
872
0
        };
descriptor.cpp:CScript miniscript::Node<unsigned int>::ToScript<(anonymous namespace)::ScriptMaker>((anonymous namespace)::ScriptMaker const&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, std::span<CScript, 18446744073709551615ul>)::operator()(bool, miniscript::Node<unsigned int> const&, std::span<CScript, 18446744073709551615ul>) const
Line
Count
Source
815
1.66M
        auto upfn = [&ctx, is_tapscript](bool verify, const Node& node, std::span<CScript> subs) -> CScript {
816
1.66M
            switch (node.fragment) {
817
2.33k
                case Fragment::PK_K: return BuildScript(ctx.ToPKBytes(node.keys[0]));
818
512
                case Fragment::PK_H: return BuildScript(OP_DUP, OP_HASH160, ctx.ToPKHBytes(node.keys[0]), OP_EQUALVERIFY);
819
424
                case Fragment::OLDER: return BuildScript(node.k, OP_CHECKSEQUENCEVERIFY);
820
935
                case Fragment::AFTER: return BuildScript(node.k, OP_CHECKLOCKTIMEVERIFY);
821
70
                case Fragment::SHA256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_SHA256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
822
92
                case Fragment::RIPEMD160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_RIPEMD160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
823
120
                case Fragment::HASH256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
824
99
                case Fragment::HASH160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
825
485
                case Fragment::WRAP_A: return BuildScript(OP_TOALTSTACK, subs[0], OP_FROMALTSTACK);
826
1.49k
                case Fragment::WRAP_S: return BuildScript(OP_SWAP, subs[0]);
827
2.84k
                case Fragment::WRAP_C: return BuildScript(std::move(subs[0]), verify ? OP_CHECKSIGVERIFY : OP_CHECKSIG);
828
130
                case Fragment::WRAP_D: return BuildScript(OP_DUP, OP_IF, subs[0], OP_ENDIF);
829
1.04k
                case Fragment::WRAP_V: {
830
1.04k
                    if (node.subs[0].GetType() << "x"_mst) {
831
160
                        return BuildScript(std::move(subs[0]), OP_VERIFY);
832
884
                    } else {
833
884
                        return std::move(subs[0]);
834
884
                    }
835
1.04k
                }
836
0
                case Fragment::WRAP_J: return BuildScript(OP_SIZE, OP_0NOTEQUAL, OP_IF, subs[0], OP_ENDIF);
837
1.64M
                case Fragment::WRAP_N: return BuildScript(std::move(subs[0]), OP_0NOTEQUAL);
838
5
                case Fragment::JUST_1: return BuildScript(OP_1);
839
893
                case Fragment::JUST_0: return BuildScript(OP_0);
840
914
                case Fragment::AND_V: return BuildScript(std::move(subs[0]), subs[1]);
841
172
                case Fragment::AND_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLAND);
842
89
                case Fragment::OR_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLOR);
843
105
                case Fragment::OR_D: return BuildScript(std::move(subs[0]), OP_IFDUP, OP_NOTIF, subs[1], OP_ENDIF);
844
39
                case Fragment::OR_C: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[1], OP_ENDIF);
845
816
                case Fragment::OR_I: return BuildScript(OP_IF, subs[0], OP_ELSE, subs[1], OP_ENDIF);
846
175
                case Fragment::ANDOR: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[2], OP_ELSE, subs[1], OP_ENDIF);
847
176
                case Fragment::MULTI: {
848
176
                    CHECK_NONFATAL(!is_tapscript);
849
176
                    CScript script = BuildScript(node.k);
850
376
                    for (const auto& key : node.keys) {
851
376
                        script = BuildScript(std::move(script), ctx.ToPKBytes(key));
852
376
                    }
853
176
                    return BuildScript(std::move(script), node.keys.size(), verify ? OP_CHECKMULTISIGVERIFY : OP_CHECKMULTISIG);
854
1.04k
                }
855
46
                case Fragment::MULTI_A: {
856
46
                    CHECK_NONFATAL(is_tapscript);
857
46
                    CScript script = BuildScript(ctx.ToPKBytes(*node.keys.begin()), OP_CHECKSIG);
858
128
                    for (auto it = node.keys.begin() + 1; it != node.keys.end(); ++it) {
859
82
                        script = BuildScript(std::move(script), ctx.ToPKBytes(*it), OP_CHECKSIGADD);
860
82
                    }
861
46
                    return BuildScript(std::move(script), node.k, verify ? OP_NUMEQUALVERIFY : OP_NUMEQUAL);
862
1.04k
                }
863
500
                case Fragment::THRESH: {
864
500
                    CScript script = std::move(subs[0]);
865
2.21k
                    for (size_t i = 1; i < subs.size(); ++i) {
866
1.71k
                        script = BuildScript(std::move(script), subs[i], OP_ADD);
867
1.71k
                    }
868
500
                    return BuildScript(std::move(script), node.k, verify ? OP_EQUALVERIFY : OP_EQUAL);
869
1.04k
                }
870
1.66M
            }
871
1.66M
            assert(false);
872
0
        };
873
1.88k
        return TreeEval<CScript>(false, downfn, upfn);
874
1.88k
    }
miniscript_tests.cpp:CScript miniscript::Node<CPubKey>::ToScript<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const
Line
Count
Source
799
375
    {
800
        // To construct the CScript for a Miniscript object, we use the TreeEval algorithm.
801
        // The State is a boolean: whether or not the node's script expansion is followed
802
        // by an OP_VERIFY (which may need to be combined with the last script opcode).
803
375
        auto downfn = [](bool verify, const Node& node, size_t index) {
804
            // For WRAP_V, the subexpression is certainly followed by OP_VERIFY.
805
375
            if (node.fragment == Fragment::WRAP_V) return true;
806
            // The subexpression of WRAP_S, and the last subexpression of AND_V
807
            // inherit the followed-by-OP_VERIFY property from the parent.
808
375
            if (node.fragment == Fragment::WRAP_S ||
809
375
                (node.fragment == Fragment::AND_V && index == 1)) return verify;
810
375
            return false;
811
375
        };
812
        // The upward function computes for a node, given its followed-by-OP_VERIFY status
813
        // and the CScripts of its child nodes, the CScript of the node.
814
375
        const bool is_tapscript{IsTapscript(m_script_ctx)};
815
375
        auto upfn = [&ctx, is_tapscript](bool verify, const Node& node, std::span<CScript> subs) -> CScript {
816
375
            switch (node.fragment) {
817
375
                case Fragment::PK_K: return BuildScript(ctx.ToPKBytes(node.keys[0]));
818
375
                case Fragment::PK_H: return BuildScript(OP_DUP, OP_HASH160, ctx.ToPKHBytes(node.keys[0]), OP_EQUALVERIFY);
819
375
                case Fragment::OLDER: return BuildScript(node.k, OP_CHECKSEQUENCEVERIFY);
820
375
                case Fragment::AFTER: return BuildScript(node.k, OP_CHECKLOCKTIMEVERIFY);
821
375
                case Fragment::SHA256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_SHA256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
822
375
                case Fragment::RIPEMD160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_RIPEMD160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
823
375
                case Fragment::HASH256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
824
375
                case Fragment::HASH160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
825
375
                case Fragment::WRAP_A: return BuildScript(OP_TOALTSTACK, subs[0], OP_FROMALTSTACK);
826
375
                case Fragment::WRAP_S: return BuildScript(OP_SWAP, subs[0]);
827
375
                case Fragment::WRAP_C: return BuildScript(std::move(subs[0]), verify ? OP_CHECKSIGVERIFY : OP_CHECKSIG);
828
375
                case Fragment::WRAP_D: return BuildScript(OP_DUP, OP_IF, subs[0], OP_ENDIF);
829
375
                case Fragment::WRAP_V: {
830
375
                    if (node.subs[0].GetType() << "x"_mst) {
831
375
                        return BuildScript(std::move(subs[0]), OP_VERIFY);
832
375
                    } else {
833
375
                        return std::move(subs[0]);
834
375
                    }
835
375
                }
836
375
                case Fragment::WRAP_J: return BuildScript(OP_SIZE, OP_0NOTEQUAL, OP_IF, subs[0], OP_ENDIF);
837
375
                case Fragment::WRAP_N: return BuildScript(std::move(subs[0]), OP_0NOTEQUAL);
838
375
                case Fragment::JUST_1: return BuildScript(OP_1);
839
375
                case Fragment::JUST_0: return BuildScript(OP_0);
840
375
                case Fragment::AND_V: return BuildScript(std::move(subs[0]), subs[1]);
841
375
                case Fragment::AND_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLAND);
842
375
                case Fragment::OR_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLOR);
843
375
                case Fragment::OR_D: return BuildScript(std::move(subs[0]), OP_IFDUP, OP_NOTIF, subs[1], OP_ENDIF);
844
375
                case Fragment::OR_C: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[1], OP_ENDIF);
845
375
                case Fragment::OR_I: return BuildScript(OP_IF, subs[0], OP_ELSE, subs[1], OP_ENDIF);
846
375
                case Fragment::ANDOR: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[2], OP_ELSE, subs[1], OP_ENDIF);
847
375
                case Fragment::MULTI: {
848
375
                    CHECK_NONFATAL(!is_tapscript);
849
375
                    CScript script = BuildScript(node.k);
850
375
                    for (const auto& key : node.keys) {
851
375
                        script = BuildScript(std::move(script), ctx.ToPKBytes(key));
852
375
                    }
853
375
                    return BuildScript(std::move(script), node.keys.size(), verify ? OP_CHECKMULTISIGVERIFY : OP_CHECKMULTISIG);
854
375
                }
855
375
                case Fragment::MULTI_A: {
856
375
                    CHECK_NONFATAL(is_tapscript);
857
375
                    CScript script = BuildScript(ctx.ToPKBytes(*node.keys.begin()), OP_CHECKSIG);
858
375
                    for (auto it = node.keys.begin() + 1; it != node.keys.end(); ++it) {
859
375
                        script = BuildScript(std::move(script), ctx.ToPKBytes(*it), OP_CHECKSIGADD);
860
375
                    }
861
375
                    return BuildScript(std::move(script), node.k, verify ? OP_NUMEQUALVERIFY : OP_NUMEQUAL);
862
375
                }
863
375
                case Fragment::THRESH: {
864
375
                    CScript script = std::move(subs[0]);
865
375
                    for (size_t i = 1; i < subs.size(); ++i) {
866
375
                        script = BuildScript(std::move(script), subs[i], OP_ADD);
867
375
                    }
868
375
                    return BuildScript(std::move(script), node.k, verify ? OP_EQUALVERIFY : OP_EQUAL);
869
375
                }
870
375
            }
871
375
            assert(false);
872
375
        };
873
375
        return TreeEval<CScript>(false, downfn, upfn);
874
375
    }
descriptor.cpp:CScript miniscript::Node<unsigned int>::ToScript<(anonymous namespace)::ScriptMaker>((anonymous namespace)::ScriptMaker const&) const
Line
Count
Source
799
1.50k
    {
800
        // To construct the CScript for a Miniscript object, we use the TreeEval algorithm.
801
        // The State is a boolean: whether or not the node's script expansion is followed
802
        // by an OP_VERIFY (which may need to be combined with the last script opcode).
803
1.50k
        auto downfn = [](bool verify, const Node& node, size_t index) {
804
            // For WRAP_V, the subexpression is certainly followed by OP_VERIFY.
805
1.50k
            if (node.fragment == Fragment::WRAP_V) return true;
806
            // The subexpression of WRAP_S, and the last subexpression of AND_V
807
            // inherit the followed-by-OP_VERIFY property from the parent.
808
1.50k
            if (node.fragment == Fragment::WRAP_S ||
809
1.50k
                (node.fragment == Fragment::AND_V && index == 1)) return verify;
810
1.50k
            return false;
811
1.50k
        };
812
        // The upward function computes for a node, given its followed-by-OP_VERIFY status
813
        // and the CScripts of its child nodes, the CScript of the node.
814
1.50k
        const bool is_tapscript{IsTapscript(m_script_ctx)};
815
1.50k
        auto upfn = [&ctx, is_tapscript](bool verify, const Node& node, std::span<CScript> subs) -> CScript {
816
1.50k
            switch (node.fragment) {
817
1.50k
                case Fragment::PK_K: return BuildScript(ctx.ToPKBytes(node.keys[0]));
818
1.50k
                case Fragment::PK_H: return BuildScript(OP_DUP, OP_HASH160, ctx.ToPKHBytes(node.keys[0]), OP_EQUALVERIFY);
819
1.50k
                case Fragment::OLDER: return BuildScript(node.k, OP_CHECKSEQUENCEVERIFY);
820
1.50k
                case Fragment::AFTER: return BuildScript(node.k, OP_CHECKLOCKTIMEVERIFY);
821
1.50k
                case Fragment::SHA256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_SHA256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
822
1.50k
                case Fragment::RIPEMD160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_RIPEMD160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
823
1.50k
                case Fragment::HASH256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
824
1.50k
                case Fragment::HASH160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
825
1.50k
                case Fragment::WRAP_A: return BuildScript(OP_TOALTSTACK, subs[0], OP_FROMALTSTACK);
826
1.50k
                case Fragment::WRAP_S: return BuildScript(OP_SWAP, subs[0]);
827
1.50k
                case Fragment::WRAP_C: return BuildScript(std::move(subs[0]), verify ? OP_CHECKSIGVERIFY : OP_CHECKSIG);
828
1.50k
                case Fragment::WRAP_D: return BuildScript(OP_DUP, OP_IF, subs[0], OP_ENDIF);
829
1.50k
                case Fragment::WRAP_V: {
830
1.50k
                    if (node.subs[0].GetType() << "x"_mst) {
831
1.50k
                        return BuildScript(std::move(subs[0]), OP_VERIFY);
832
1.50k
                    } else {
833
1.50k
                        return std::move(subs[0]);
834
1.50k
                    }
835
1.50k
                }
836
1.50k
                case Fragment::WRAP_J: return BuildScript(OP_SIZE, OP_0NOTEQUAL, OP_IF, subs[0], OP_ENDIF);
837
1.50k
                case Fragment::WRAP_N: return BuildScript(std::move(subs[0]), OP_0NOTEQUAL);
838
1.50k
                case Fragment::JUST_1: return BuildScript(OP_1);
839
1.50k
                case Fragment::JUST_0: return BuildScript(OP_0);
840
1.50k
                case Fragment::AND_V: return BuildScript(std::move(subs[0]), subs[1]);
841
1.50k
                case Fragment::AND_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLAND);
842
1.50k
                case Fragment::OR_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLOR);
843
1.50k
                case Fragment::OR_D: return BuildScript(std::move(subs[0]), OP_IFDUP, OP_NOTIF, subs[1], OP_ENDIF);
844
1.50k
                case Fragment::OR_C: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[1], OP_ENDIF);
845
1.50k
                case Fragment::OR_I: return BuildScript(OP_IF, subs[0], OP_ELSE, subs[1], OP_ENDIF);
846
1.50k
                case Fragment::ANDOR: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[2], OP_ELSE, subs[1], OP_ENDIF);
847
1.50k
                case Fragment::MULTI: {
848
1.50k
                    CHECK_NONFATAL(!is_tapscript);
849
1.50k
                    CScript script = BuildScript(node.k);
850
1.50k
                    for (const auto& key : node.keys) {
851
1.50k
                        script = BuildScript(std::move(script), ctx.ToPKBytes(key));
852
1.50k
                    }
853
1.50k
                    return BuildScript(std::move(script), node.keys.size(), verify ? OP_CHECKMULTISIGVERIFY : OP_CHECKMULTISIG);
854
1.50k
                }
855
1.50k
                case Fragment::MULTI_A: {
856
1.50k
                    CHECK_NONFATAL(is_tapscript);
857
1.50k
                    CScript script = BuildScript(ctx.ToPKBytes(*node.keys.begin()), OP_CHECKSIG);
858
1.50k
                    for (auto it = node.keys.begin() + 1; it != node.keys.end(); ++it) {
859
1.50k
                        script = BuildScript(std::move(script), ctx.ToPKBytes(*it), OP_CHECKSIGADD);
860
1.50k
                    }
861
1.50k
                    return BuildScript(std::move(script), node.k, verify ? OP_NUMEQUALVERIFY : OP_NUMEQUAL);
862
1.50k
                }
863
1.50k
                case Fragment::THRESH: {
864
1.50k
                    CScript script = std::move(subs[0]);
865
1.50k
                    for (size_t i = 1; i < subs.size(); ++i) {
866
1.50k
                        script = BuildScript(std::move(script), subs[i], OP_ADD);
867
1.50k
                    }
868
1.50k
                    return BuildScript(std::move(script), node.k, verify ? OP_EQUALVERIFY : OP_EQUAL);
869
1.50k
                }
870
1.50k
            }
871
1.50k
            assert(false);
872
1.50k
        };
873
1.50k
        return TreeEval<CScript>(false, downfn, upfn);
874
1.50k
    }
875
876
    template<typename CTx>
877
15
    std::optional<std::string> ToString(const CTx& ctx) const {
878
15
        bool dummy{false};
879
15
        return ToString(ctx, dummy);
880
15
    }
miniscript_tests.cpp:std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<CPubKey>::ToString<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const
Line
Count
Source
877
1
    std::optional<std::string> ToString(const CTx& ctx) const {
878
1
        bool dummy{false};
879
1
        return ToString(ctx, dummy);
880
1
    }
descriptor.cpp:std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<unsigned int>::ToString<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const
Line
Count
Source
877
14
    std::optional<std::string> ToString(const CTx& ctx) const {
878
14
        bool dummy{false};
879
14
        return ToString(ctx, dummy);
880
14
    }
881
882
    template<typename CTx>
883
1.12k
    std::optional<std::string> ToString(const CTx& ctx, bool& has_priv_key) const {
884
        // To construct the std::string representation for a Miniscript object, we use
885
        // the TreeEvalMaybe algorithm. The State is a boolean: whether the parent node is a
886
        // wrapper. If so, non-wrapper expressions must be prefixed with a ":".
887
2.97M
        auto downfn = [](bool, const Node& node, size_t) {
888
2.97M
            return (node.fragment == Fragment::WRAP_A || node.fragment == Fragment::WRAP_S ||
889
2.97M
                    node.fragment == Fragment::WRAP_D || node.fragment == Fragment::WRAP_V ||
890
2.97M
                    node.fragment == Fragment::WRAP_J || node.fragment == Fragment::WRAP_N ||
891
2.97M
                    node.fragment == Fragment::WRAP_C ||
892
2.97M
                    (node.fragment == Fragment::AND_V && node.subs[1].fragment == Fragment::JUST_1) ||
893
2.97M
                    (node.fragment == Fragment::OR_I && node.subs[0].fragment == Fragment::JUST_0) ||
894
2.97M
                    (node.fragment == Fragment::OR_I && node.subs[1].fragment == Fragment::JUST_0));
895
2.97M
        };
miniscript_tests.cpp:std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<CPubKey>::ToString<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&, bool&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, unsigned long)::operator()(bool, miniscript::Node<CPubKey> const&, unsigned long) const
Line
Count
Source
887
3
        auto downfn = [](bool, const Node& node, size_t) {
888
3
            return (node.fragment == Fragment::WRAP_A || node.fragment == Fragment::WRAP_S ||
889
3
                    node.fragment == Fragment::WRAP_D || node.fragment == Fragment::WRAP_V ||
890
3
                    node.fragment == Fragment::WRAP_J || node.fragment == Fragment::WRAP_N ||
891
3
                    node.fragment == Fragment::WRAP_C ||
892
3
                    (node.fragment == Fragment::AND_V && node.subs[1].fragment == Fragment::JUST_1) ||
893
3
                    (node.fragment == Fragment::OR_I && node.subs[0].fragment == Fragment::JUST_0) ||
894
3
                    (node.fragment == Fragment::OR_I && node.subs[1].fragment == Fragment::JUST_0));
895
3
        };
descriptor.cpp:std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<unsigned int>::ToString<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&, bool&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, unsigned long)::operator()(bool, miniscript::Node<unsigned int> const&, unsigned long) const
Line
Count
Source
887
65
        auto downfn = [](bool, const Node& node, size_t) {
888
65
            return (node.fragment == Fragment::WRAP_A || node.fragment == Fragment::WRAP_S ||
889
65
                    node.fragment == Fragment::WRAP_D || node.fragment == Fragment::WRAP_V ||
890
65
                    node.fragment == Fragment::WRAP_J || node.fragment == Fragment::WRAP_N ||
891
65
                    node.fragment == Fragment::WRAP_C ||
892
65
                    (node.fragment == Fragment::AND_V && node.subs[1].fragment == Fragment::JUST_1) ||
893
65
                    (node.fragment == Fragment::OR_I && node.subs[0].fragment == Fragment::JUST_0) ||
894
65
                    (node.fragment == Fragment::OR_I && node.subs[1].fragment == Fragment::JUST_0));
895
65
        };
descriptor.cpp:std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<unsigned int>::ToString<(anonymous namespace)::StringMaker>((anonymous namespace)::StringMaker const&, bool&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, unsigned long)::operator()(bool, miniscript::Node<unsigned int> const&, unsigned long) const
Line
Count
Source
887
2.97M
        auto downfn = [](bool, const Node& node, size_t) {
888
2.97M
            return (node.fragment == Fragment::WRAP_A || node.fragment == Fragment::WRAP_S ||
889
2.97M
                    node.fragment == Fragment::WRAP_D || node.fragment == Fragment::WRAP_V ||
890
2.97M
                    node.fragment == Fragment::WRAP_J || node.fragment == Fragment::WRAP_N ||
891
2.97M
                    node.fragment == Fragment::WRAP_C ||
892
2.97M
                    (node.fragment == Fragment::AND_V && node.subs[1].fragment == Fragment::JUST_1) ||
893
2.97M
                    (node.fragment == Fragment::OR_I && node.subs[0].fragment == Fragment::JUST_0) ||
894
2.97M
                    (node.fragment == Fragment::OR_I && node.subs[1].fragment == Fragment::JUST_0));
895
2.97M
        };
896
5.22k
        auto toString = [&ctx, &has_priv_key](Key key) -> std::optional<std::string> {
897
5.22k
            bool fragment_has_priv_key{false};
898
5.22k
            auto key_str{ctx.ToString(key, fragment_has_priv_key)};
899
5.22k
            if (key_str) has_priv_key = has_priv_key || fragment_has_priv_key;
900
5.22k
            return key_str;
901
5.22k
        };
Unexecuted instantiation: miniscript_tests.cpp:std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<CPubKey>::ToString<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&, bool&) const::'lambda'(CPubKey)::operator()[abi:cxx11](CPubKey) const
descriptor.cpp:std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<unsigned int>::ToString<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&, bool&) const::'lambda'(unsigned int)::operator()[abi:cxx11](unsigned int) const
Line
Count
Source
896
30
        auto toString = [&ctx, &has_priv_key](Key key) -> std::optional<std::string> {
897
30
            bool fragment_has_priv_key{false};
898
30
            auto key_str{ctx.ToString(key, fragment_has_priv_key)};
899
30
            if (key_str) has_priv_key = has_priv_key || fragment_has_priv_key;
900
30
            return key_str;
901
30
        };
descriptor.cpp:std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<unsigned int>::ToString<(anonymous namespace)::StringMaker>((anonymous namespace)::StringMaker const&, bool&) const::'lambda'(unsigned int)::operator()[abi:cxx11](unsigned int) const
Line
Count
Source
896
5.19k
        auto toString = [&ctx, &has_priv_key](Key key) -> std::optional<std::string> {
897
5.19k
            bool fragment_has_priv_key{false};
898
5.19k
            auto key_str{ctx.ToString(key, fragment_has_priv_key)};
899
5.19k
            if (key_str) has_priv_key = has_priv_key || fragment_has_priv_key;
900
5.19k
            return key_str;
901
5.19k
        };
902
        // The upward function computes for a node, given whether its parent is a wrapper,
903
        // and the string representations of its child nodes, the string representation of the node.
904
1.12k
        const bool is_tapscript{IsTapscript(m_script_ctx)};
905
2.97M
        auto upfn = [is_tapscript, &toString](bool wrapped, const Node& node, std::span<std::string> subs) -> std::optional<std::string> {
906
2.97M
            std::string ret = wrapped ? ":" : "";
907
908
2.97M
            switch (node.fragment) {
909
609
                case Fragment::WRAP_A: return "a" + std::move(subs[0]);
910
356
                case Fragment::WRAP_S: return "s" + std::move(subs[0]);
911
2.42k
                case Fragment::WRAP_C:
912
2.42k
                    if (node.subs[0].fragment == Fragment::PK_K) {
913
                        // pk(K) is syntactic sugar for c:pk_k(K)
914
1.77k
                        auto key_str = toString(node.subs[0].keys[0]);
915
1.77k
                        if (!key_str) return {};
916
1.77k
                        return std::move(ret) + "pk(" + std::move(*key_str) + ")";
917
1.77k
                    }
918
647
                    if (node.subs[0].fragment == Fragment::PK_H) {
919
                        // pkh(K) is syntactic sugar for c:pk_h(K)
920
625
                        auto key_str = toString(node.subs[0].keys[0]);
921
625
                        if (!key_str) return {};
922
625
                        return std::move(ret) + "pkh(" + std::move(*key_str) + ")";
923
625
                    }
924
22
                    return "c" + std::move(subs[0]);
925
84
                case Fragment::WRAP_D: return "d" + std::move(subs[0]);
926
1.08k
                case Fragment::WRAP_V: return "v" + std::move(subs[0]);
927
0
                case Fragment::WRAP_J: return "j" + std::move(subs[0]);
928
2.96M
                case Fragment::WRAP_N: return "n" + std::move(subs[0]);
929
997
                case Fragment::AND_V:
930
                    // t:X is syntactic sugar for and_v(X,1).
931
997
                    if (node.subs[1].fragment == Fragment::JUST_1) return "t" + std::move(subs[0]);
932
991
                    break;
933
991
                case Fragment::OR_I:
934
229
                    if (node.subs[0].fragment == Fragment::JUST_0) return "l" + std::move(subs[1]);
935
108
                    if (node.subs[1].fragment == Fragment::JUST_0) return "u" + std::move(subs[0]);
936
108
                    break;
937
4.75k
                default: break;
938
2.97M
            }
939
5.85k
            switch (node.fragment) {
940
1.82k
                case Fragment::PK_K: {
941
1.82k
                    auto key_str = toString(node.keys[0]);
942
1.82k
                    if (!key_str) return {};
943
1.82k
                    return std::move(ret) + "pk_k(" + std::move(*key_str) + ")";
944
1.82k
                }
945
625
                case Fragment::PK_H: {
946
625
                    auto key_str = toString(node.keys[0]);
947
625
                    if (!key_str) return {};
948
625
                    return std::move(ret) + "pk_h(" + std::move(*key_str) + ")";
949
625
                }
950
436
                case Fragment::AFTER: return std::move(ret) + "after(" + util::ToString(node.k) + ")";
951
400
                case Fragment::OLDER: return std::move(ret) + "older(" + util::ToString(node.k) + ")";
952
30
                case Fragment::HASH256: return std::move(ret) + "hash256(" + HexStr(node.data) + ")";
953
63
                case Fragment::HASH160: return std::move(ret) + "hash160(" + HexStr(node.data) + ")";
954
71
                case Fragment::SHA256: return std::move(ret) + "sha256(" + HexStr(node.data) + ")";
955
35
                case Fragment::RIPEMD160: return std::move(ret) + "ripemd160(" + HexStr(node.data) + ")";
956
7
                case Fragment::JUST_1: return std::move(ret) + "1";
957
162
                case Fragment::JUST_0: return std::move(ret) + "0";
958
991
                case Fragment::AND_V: return std::move(ret) + "and_v(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
959
368
                case Fragment::AND_B: return std::move(ret) + "and_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
960
80
                case Fragment::OR_B: return std::move(ret) + "or_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
961
77
                case Fragment::OR_D: return std::move(ret) + "or_d(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
962
42
                case Fragment::OR_C: return std::move(ret) + "or_c(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
963
108
                case Fragment::OR_I: return std::move(ret) + "or_i(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
964
182
                case Fragment::ANDOR:
965
                    // and_n(X,Y) is syntactic sugar for andor(X,Y,0).
966
182
                    if (node.subs[2].fragment == Fragment::JUST_0) return std::move(ret) + "and_n(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
967
142
                    return std::move(ret) + "andor(" + std::move(subs[0]) + "," + std::move(subs[1]) + "," + std::move(subs[2]) + ")";
968
96
                case Fragment::MULTI: {
969
96
                    CHECK_NONFATAL(!is_tapscript);
970
96
                    auto str = std::move(ret) + "multi(" + util::ToString(node.k);
971
246
                    for (const auto& key : node.keys) {
972
246
                        auto key_str = toString(key);
973
246
                        if (!key_str) return {};
974
246
                        str += "," + std::move(*key_str);
975
246
                    }
976
96
                    return std::move(str) + ")";
977
96
                }
978
51
                case Fragment::MULTI_A: {
979
51
                    CHECK_NONFATAL(is_tapscript);
980
51
                    auto str = std::move(ret) + "multi_a(" + util::ToString(node.k);
981
130
                    for (const auto& key : node.keys) {
982
130
                        auto key_str = toString(key);
983
130
                        if (!key_str) return {};
984
130
                        str += "," + std::move(*key_str);
985
130
                    }
986
51
                    return std::move(str) + ")";
987
51
                }
988
211
                case Fragment::THRESH: {
989
211
                    auto str = std::move(ret) + "thresh(" + util::ToString(node.k);
990
730
                    for (auto& sub : subs) {
991
730
                        str += "," + std::move(sub);
992
730
                    }
993
211
                    return std::move(str) + ")";
994
51
                }
995
0
                default: break;
996
5.85k
            }
997
5.85k
            assert(false);
998
0
        };
miniscript_tests.cpp:std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<CPubKey>::ToString<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&, bool&) const::'lambda'(bool, miniscript::Node<CPubKey> const&, std::span<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, 18446744073709551615ul>)::operator()[abi:cxx11](bool, miniscript::Node<CPubKey> const&, std::span<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, 18446744073709551615ul>) const
Line
Count
Source
905
4
        auto upfn = [is_tapscript, &toString](bool wrapped, const Node& node, std::span<std::string> subs) -> std::optional<std::string> {
906
4
            std::string ret = wrapped ? ":" : "";
907
908
4
            switch (node.fragment) {
909
1
                case Fragment::WRAP_A: return "a" + std::move(subs[0]);
910
0
                case Fragment::WRAP_S: return "s" + std::move(subs[0]);
911
0
                case Fragment::WRAP_C:
912
0
                    if (node.subs[0].fragment == Fragment::PK_K) {
913
                        // pk(K) is syntactic sugar for c:pk_k(K)
914
0
                        auto key_str = toString(node.subs[0].keys[0]);
915
0
                        if (!key_str) return {};
916
0
                        return std::move(ret) + "pk(" + std::move(*key_str) + ")";
917
0
                    }
918
0
                    if (node.subs[0].fragment == Fragment::PK_H) {
919
                        // pkh(K) is syntactic sugar for c:pk_h(K)
920
0
                        auto key_str = toString(node.subs[0].keys[0]);
921
0
                        if (!key_str) return {};
922
0
                        return std::move(ret) + "pkh(" + std::move(*key_str) + ")";
923
0
                    }
924
0
                    return "c" + std::move(subs[0]);
925
0
                case Fragment::WRAP_D: return "d" + std::move(subs[0]);
926
0
                case Fragment::WRAP_V: return "v" + std::move(subs[0]);
927
0
                case Fragment::WRAP_J: return "j" + std::move(subs[0]);
928
0
                case Fragment::WRAP_N: return "n" + std::move(subs[0]);
929
0
                case Fragment::AND_V:
930
                    // t:X is syntactic sugar for and_v(X,1).
931
0
                    if (node.subs[1].fragment == Fragment::JUST_1) return "t" + std::move(subs[0]);
932
0
                    break;
933
0
                case Fragment::OR_I:
934
0
                    if (node.subs[0].fragment == Fragment::JUST_0) return "l" + std::move(subs[1]);
935
0
                    if (node.subs[1].fragment == Fragment::JUST_0) return "u" + std::move(subs[0]);
936
0
                    break;
937
3
                default: break;
938
4
            }
939
3
            switch (node.fragment) {
940
0
                case Fragment::PK_K: {
941
0
                    auto key_str = toString(node.keys[0]);
942
0
                    if (!key_str) return {};
943
0
                    return std::move(ret) + "pk_k(" + std::move(*key_str) + ")";
944
0
                }
945
0
                case Fragment::PK_H: {
946
0
                    auto key_str = toString(node.keys[0]);
947
0
                    if (!key_str) return {};
948
0
                    return std::move(ret) + "pk_h(" + std::move(*key_str) + ")";
949
0
                }
950
2
                case Fragment::AFTER: return std::move(ret) + "after(" + util::ToString(node.k) + ")";
951
0
                case Fragment::OLDER: return std::move(ret) + "older(" + util::ToString(node.k) + ")";
952
0
                case Fragment::HASH256: return std::move(ret) + "hash256(" + HexStr(node.data) + ")";
953
0
                case Fragment::HASH160: return std::move(ret) + "hash160(" + HexStr(node.data) + ")";
954
0
                case Fragment::SHA256: return std::move(ret) + "sha256(" + HexStr(node.data) + ")";
955
0
                case Fragment::RIPEMD160: return std::move(ret) + "ripemd160(" + HexStr(node.data) + ")";
956
0
                case Fragment::JUST_1: return std::move(ret) + "1";
957
0
                case Fragment::JUST_0: return std::move(ret) + "0";
958
0
                case Fragment::AND_V: return std::move(ret) + "and_v(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
959
1
                case Fragment::AND_B: return std::move(ret) + "and_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
960
0
                case Fragment::OR_B: return std::move(ret) + "or_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
961
0
                case Fragment::OR_D: return std::move(ret) + "or_d(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
962
0
                case Fragment::OR_C: return std::move(ret) + "or_c(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
963
0
                case Fragment::OR_I: return std::move(ret) + "or_i(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
964
0
                case Fragment::ANDOR:
965
                    // and_n(X,Y) is syntactic sugar for andor(X,Y,0).
966
0
                    if (node.subs[2].fragment == Fragment::JUST_0) return std::move(ret) + "and_n(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
967
0
                    return std::move(ret) + "andor(" + std::move(subs[0]) + "," + std::move(subs[1]) + "," + std::move(subs[2]) + ")";
968
0
                case Fragment::MULTI: {
969
0
                    CHECK_NONFATAL(!is_tapscript);
970
0
                    auto str = std::move(ret) + "multi(" + util::ToString(node.k);
971
0
                    for (const auto& key : node.keys) {
972
0
                        auto key_str = toString(key);
973
0
                        if (!key_str) return {};
974
0
                        str += "," + std::move(*key_str);
975
0
                    }
976
0
                    return std::move(str) + ")";
977
0
                }
978
0
                case Fragment::MULTI_A: {
979
0
                    CHECK_NONFATAL(is_tapscript);
980
0
                    auto str = std::move(ret) + "multi_a(" + util::ToString(node.k);
981
0
                    for (const auto& key : node.keys) {
982
0
                        auto key_str = toString(key);
983
0
                        if (!key_str) return {};
984
0
                        str += "," + std::move(*key_str);
985
0
                    }
986
0
                    return std::move(str) + ")";
987
0
                }
988
0
                case Fragment::THRESH: {
989
0
                    auto str = std::move(ret) + "thresh(" + util::ToString(node.k);
990
0
                    for (auto& sub : subs) {
991
0
                        str += "," + std::move(sub);
992
0
                    }
993
0
                    return std::move(str) + ")";
994
0
                }
995
0
                default: break;
996
3
            }
997
3
            assert(false);
998
0
        };
descriptor.cpp:std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<unsigned int>::ToString<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&, bool&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, std::span<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, 18446744073709551615ul>)::operator()[abi:cxx11](bool, miniscript::Node<unsigned int> const&, std::span<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, 18446744073709551615ul>) const
Line
Count
Source
905
79
        auto upfn = [is_tapscript, &toString](bool wrapped, const Node& node, std::span<std::string> subs) -> std::optional<std::string> {
906
79
            std::string ret = wrapped ? ":" : "";
907
908
79
            switch (node.fragment) {
909
3
                case Fragment::WRAP_A: return "a" + std::move(subs[0]);
910
6
                case Fragment::WRAP_S: return "s" + std::move(subs[0]);
911
14
                case Fragment::WRAP_C:
912
14
                    if (node.subs[0].fragment == Fragment::PK_K) {
913
                        // pk(K) is syntactic sugar for c:pk_k(K)
914
10
                        auto key_str = toString(node.subs[0].keys[0]);
915
10
                        if (!key_str) return {};
916
10
                        return std::move(ret) + "pk(" + std::move(*key_str) + ")";
917
10
                    }
918
4
                    if (node.subs[0].fragment == Fragment::PK_H) {
919
                        // pkh(K) is syntactic sugar for c:pk_h(K)
920
2
                        auto key_str = toString(node.subs[0].keys[0]);
921
2
                        if (!key_str) return {};
922
2
                        return std::move(ret) + "pkh(" + std::move(*key_str) + ")";
923
2
                    }
924
2
                    return "c" + std::move(subs[0]);
925
0
                case Fragment::WRAP_D: return "d" + std::move(subs[0]);
926
6
                case Fragment::WRAP_V: return "v" + std::move(subs[0]);
927
0
                case Fragment::WRAP_J: return "j" + std::move(subs[0]);
928
0
                case Fragment::WRAP_N: return "n" + std::move(subs[0]);
929
2
                case Fragment::AND_V:
930
                    // t:X is syntactic sugar for and_v(X,1).
931
2
                    if (node.subs[1].fragment == Fragment::JUST_1) return "t" + std::move(subs[0]);
932
2
                    break;
933
2
                case Fragment::OR_I:
934
2
                    if (node.subs[0].fragment == Fragment::JUST_0) return "l" + std::move(subs[1]);
935
2
                    if (node.subs[1].fragment == Fragment::JUST_0) return "u" + std::move(subs[0]);
936
2
                    break;
937
46
                default: break;
938
79
            }
939
50
            switch (node.fragment) {
940
16
                case Fragment::PK_K: {
941
16
                    auto key_str = toString(node.keys[0]);
942
16
                    if (!key_str) return {};
943
16
                    return std::move(ret) + "pk_k(" + std::move(*key_str) + ")";
944
16
                }
945
2
                case Fragment::PK_H: {
946
2
                    auto key_str = toString(node.keys[0]);
947
2
                    if (!key_str) return {};
948
2
                    return std::move(ret) + "pk_h(" + std::move(*key_str) + ")";
949
2
                }
950
2
                case Fragment::AFTER: return std::move(ret) + "after(" + util::ToString(node.k) + ")";
951
8
                case Fragment::OLDER: return std::move(ret) + "older(" + util::ToString(node.k) + ")";
952
0
                case Fragment::HASH256: return std::move(ret) + "hash256(" + HexStr(node.data) + ")";
953
0
                case Fragment::HASH160: return std::move(ret) + "hash160(" + HexStr(node.data) + ")";
954
2
                case Fragment::SHA256: return std::move(ret) + "sha256(" + HexStr(node.data) + ")";
955
1
                case Fragment::RIPEMD160: return std::move(ret) + "ripemd160(" + HexStr(node.data) + ")";
956
1
                case Fragment::JUST_1: return std::move(ret) + "1";
957
1
                case Fragment::JUST_0: return std::move(ret) + "0";
958
2
                case Fragment::AND_V: return std::move(ret) + "and_v(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
959
7
                case Fragment::AND_B: return std::move(ret) + "and_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
960
4
                case Fragment::OR_B: return std::move(ret) + "or_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
961
0
                case Fragment::OR_D: return std::move(ret) + "or_d(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
962
0
                case Fragment::OR_C: return std::move(ret) + "or_c(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
963
2
                case Fragment::OR_I: return std::move(ret) + "or_i(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
964
2
                case Fragment::ANDOR:
965
                    // and_n(X,Y) is syntactic sugar for andor(X,Y,0).
966
2
                    if (node.subs[2].fragment == Fragment::JUST_0) return std::move(ret) + "and_n(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
967
2
                    return std::move(ret) + "andor(" + std::move(subs[0]) + "," + std::move(subs[1]) + "," + std::move(subs[2]) + ")";
968
0
                case Fragment::MULTI: {
969
0
                    CHECK_NONFATAL(!is_tapscript);
970
0
                    auto str = std::move(ret) + "multi(" + util::ToString(node.k);
971
0
                    for (const auto& key : node.keys) {
972
0
                        auto key_str = toString(key);
973
0
                        if (!key_str) return {};
974
0
                        str += "," + std::move(*key_str);
975
0
                    }
976
0
                    return std::move(str) + ")";
977
0
                }
978
0
                case Fragment::MULTI_A: {
979
0
                    CHECK_NONFATAL(is_tapscript);
980
0
                    auto str = std::move(ret) + "multi_a(" + util::ToString(node.k);
981
0
                    for (const auto& key : node.keys) {
982
0
                        auto key_str = toString(key);
983
0
                        if (!key_str) return {};
984
0
                        str += "," + std::move(*key_str);
985
0
                    }
986
0
                    return std::move(str) + ")";
987
0
                }
988
0
                case Fragment::THRESH: {
989
0
                    auto str = std::move(ret) + "thresh(" + util::ToString(node.k);
990
0
                    for (auto& sub : subs) {
991
0
                        str += "," + std::move(sub);
992
0
                    }
993
0
                    return std::move(str) + ")";
994
0
                }
995
0
                default: break;
996
50
            }
997
50
            assert(false);
998
0
        };
descriptor.cpp:std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<unsigned int>::ToString<(anonymous namespace)::StringMaker>((anonymous namespace)::StringMaker const&, bool&) const::'lambda'(bool, miniscript::Node<unsigned int> const&, std::span<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, 18446744073709551615ul>)::operator()[abi:cxx11](bool, miniscript::Node<unsigned int> const&, std::span<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, 18446744073709551615ul>) const
Line
Count
Source
905
2.97M
        auto upfn = [is_tapscript, &toString](bool wrapped, const Node& node, std::span<std::string> subs) -> std::optional<std::string> {
906
2.97M
            std::string ret = wrapped ? ":" : "";
907
908
2.97M
            switch (node.fragment) {
909
605
                case Fragment::WRAP_A: return "a" + std::move(subs[0]);
910
350
                case Fragment::WRAP_S: return "s" + std::move(subs[0]);
911
2.40k
                case Fragment::WRAP_C:
912
2.40k
                    if (node.subs[0].fragment == Fragment::PK_K) {
913
                        // pk(K) is syntactic sugar for c:pk_k(K)
914
1.76k
                        auto key_str = toString(node.subs[0].keys[0]);
915
1.76k
                        if (!key_str) return {};
916
1.76k
                        return std::move(ret) + "pk(" + std::move(*key_str) + ")";
917
1.76k
                    }
918
643
                    if (node.subs[0].fragment == Fragment::PK_H) {
919
                        // pkh(K) is syntactic sugar for c:pk_h(K)
920
623
                        auto key_str = toString(node.subs[0].keys[0]);
921
623
                        if (!key_str) return {};
922
623
                        return std::move(ret) + "pkh(" + std::move(*key_str) + ")";
923
623
                    }
924
20
                    return "c" + std::move(subs[0]);
925
84
                case Fragment::WRAP_D: return "d" + std::move(subs[0]);
926
1.07k
                case Fragment::WRAP_V: return "v" + std::move(subs[0]);
927
0
                case Fragment::WRAP_J: return "j" + std::move(subs[0]);
928
2.96M
                case Fragment::WRAP_N: return "n" + std::move(subs[0]);
929
995
                case Fragment::AND_V:
930
                    // t:X is syntactic sugar for and_v(X,1).
931
995
                    if (node.subs[1].fragment == Fragment::JUST_1) return "t" + std::move(subs[0]);
932
989
                    break;
933
989
                case Fragment::OR_I:
934
227
                    if (node.subs[0].fragment == Fragment::JUST_0) return "l" + std::move(subs[1]);
935
106
                    if (node.subs[1].fragment == Fragment::JUST_0) return "u" + std::move(subs[0]);
936
106
                    break;
937
4.70k
                default: break;
938
2.97M
            }
939
5.80k
            switch (node.fragment) {
940
1.80k
                case Fragment::PK_K: {
941
1.80k
                    auto key_str = toString(node.keys[0]);
942
1.80k
                    if (!key_str) return {};
943
1.80k
                    return std::move(ret) + "pk_k(" + std::move(*key_str) + ")";
944
1.80k
                }
945
623
                case Fragment::PK_H: {
946
623
                    auto key_str = toString(node.keys[0]);
947
623
                    if (!key_str) return {};
948
623
                    return std::move(ret) + "pk_h(" + std::move(*key_str) + ")";
949
623
                }
950
432
                case Fragment::AFTER: return std::move(ret) + "after(" + util::ToString(node.k) + ")";
951
392
                case Fragment::OLDER: return std::move(ret) + "older(" + util::ToString(node.k) + ")";
952
30
                case Fragment::HASH256: return std::move(ret) + "hash256(" + HexStr(node.data) + ")";
953
63
                case Fragment::HASH160: return std::move(ret) + "hash160(" + HexStr(node.data) + ")";
954
69
                case Fragment::SHA256: return std::move(ret) + "sha256(" + HexStr(node.data) + ")";
955
34
                case Fragment::RIPEMD160: return std::move(ret) + "ripemd160(" + HexStr(node.data) + ")";
956
6
                case Fragment::JUST_1: return std::move(ret) + "1";
957
161
                case Fragment::JUST_0: return std::move(ret) + "0";
958
989
                case Fragment::AND_V: return std::move(ret) + "and_v(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
959
360
                case Fragment::AND_B: return std::move(ret) + "and_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
960
76
                case Fragment::OR_B: return std::move(ret) + "or_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
961
77
                case Fragment::OR_D: return std::move(ret) + "or_d(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
962
42
                case Fragment::OR_C: return std::move(ret) + "or_c(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
963
106
                case Fragment::OR_I: return std::move(ret) + "or_i(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
964
180
                case Fragment::ANDOR:
965
                    // and_n(X,Y) is syntactic sugar for andor(X,Y,0).
966
180
                    if (node.subs[2].fragment == Fragment::JUST_0) return std::move(ret) + "and_n(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
967
140
                    return std::move(ret) + "andor(" + std::move(subs[0]) + "," + std::move(subs[1]) + "," + std::move(subs[2]) + ")";
968
96
                case Fragment::MULTI: {
969
96
                    CHECK_NONFATAL(!is_tapscript);
970
96
                    auto str = std::move(ret) + "multi(" + util::ToString(node.k);
971
246
                    for (const auto& key : node.keys) {
972
246
                        auto key_str = toString(key);
973
246
                        if (!key_str) return {};
974
246
                        str += "," + std::move(*key_str);
975
246
                    }
976
96
                    return std::move(str) + ")";
977
96
                }
978
51
                case Fragment::MULTI_A: {
979
51
                    CHECK_NONFATAL(is_tapscript);
980
51
                    auto str = std::move(ret) + "multi_a(" + util::ToString(node.k);
981
130
                    for (const auto& key : node.keys) {
982
130
                        auto key_str = toString(key);
983
130
                        if (!key_str) return {};
984
130
                        str += "," + std::move(*key_str);
985
130
                    }
986
51
                    return std::move(str) + ")";
987
51
                }
988
211
                case Fragment::THRESH: {
989
211
                    auto str = std::move(ret) + "thresh(" + util::ToString(node.k);
990
730
                    for (auto& sub : subs) {
991
730
                        str += "," + std::move(sub);
992
730
                    }
993
211
                    return std::move(str) + ")";
994
51
                }
995
0
                default: break;
996
5.80k
            }
997
5.80k
            assert(false);
998
0
        };
999
1000
1.12k
        return TreeEvalMaybe<std::string>(false, downfn, upfn);
1001
1.12k
    }
miniscript_tests.cpp:std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<CPubKey>::ToString<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&, bool&) const
Line
Count
Source
883
1
    std::optional<std::string> ToString(const CTx& ctx, bool& has_priv_key) const {
884
        // To construct the std::string representation for a Miniscript object, we use
885
        // the TreeEvalMaybe algorithm. The State is a boolean: whether the parent node is a
886
        // wrapper. If so, non-wrapper expressions must be prefixed with a ":".
887
1
        auto downfn = [](bool, const Node& node, size_t) {
888
1
            return (node.fragment == Fragment::WRAP_A || node.fragment == Fragment::WRAP_S ||
889
1
                    node.fragment == Fragment::WRAP_D || node.fragment == Fragment::WRAP_V ||
890
1
                    node.fragment == Fragment::WRAP_J || node.fragment == Fragment::WRAP_N ||
891
1
                    node.fragment == Fragment::WRAP_C ||
892
1
                    (node.fragment == Fragment::AND_V && node.subs[1].fragment == Fragment::JUST_1) ||
893
1
                    (node.fragment == Fragment::OR_I && node.subs[0].fragment == Fragment::JUST_0) ||
894
1
                    (node.fragment == Fragment::OR_I && node.subs[1].fragment == Fragment::JUST_0));
895
1
        };
896
1
        auto toString = [&ctx, &has_priv_key](Key key) -> std::optional<std::string> {
897
1
            bool fragment_has_priv_key{false};
898
1
            auto key_str{ctx.ToString(key, fragment_has_priv_key)};
899
1
            if (key_str) has_priv_key = has_priv_key || fragment_has_priv_key;
900
1
            return key_str;
901
1
        };
902
        // The upward function computes for a node, given whether its parent is a wrapper,
903
        // and the string representations of its child nodes, the string representation of the node.
904
1
        const bool is_tapscript{IsTapscript(m_script_ctx)};
905
1
        auto upfn = [is_tapscript, &toString](bool wrapped, const Node& node, std::span<std::string> subs) -> std::optional<std::string> {
906
1
            std::string ret = wrapped ? ":" : "";
907
908
1
            switch (node.fragment) {
909
1
                case Fragment::WRAP_A: return "a" + std::move(subs[0]);
910
1
                case Fragment::WRAP_S: return "s" + std::move(subs[0]);
911
1
                case Fragment::WRAP_C:
912
1
                    if (node.subs[0].fragment == Fragment::PK_K) {
913
                        // pk(K) is syntactic sugar for c:pk_k(K)
914
1
                        auto key_str = toString(node.subs[0].keys[0]);
915
1
                        if (!key_str) return {};
916
1
                        return std::move(ret) + "pk(" + std::move(*key_str) + ")";
917
1
                    }
918
1
                    if (node.subs[0].fragment == Fragment::PK_H) {
919
                        // pkh(K) is syntactic sugar for c:pk_h(K)
920
1
                        auto key_str = toString(node.subs[0].keys[0]);
921
1
                        if (!key_str) return {};
922
1
                        return std::move(ret) + "pkh(" + std::move(*key_str) + ")";
923
1
                    }
924
1
                    return "c" + std::move(subs[0]);
925
1
                case Fragment::WRAP_D: return "d" + std::move(subs[0]);
926
1
                case Fragment::WRAP_V: return "v" + std::move(subs[0]);
927
1
                case Fragment::WRAP_J: return "j" + std::move(subs[0]);
928
1
                case Fragment::WRAP_N: return "n" + std::move(subs[0]);
929
1
                case Fragment::AND_V:
930
                    // t:X is syntactic sugar for and_v(X,1).
931
1
                    if (node.subs[1].fragment == Fragment::JUST_1) return "t" + std::move(subs[0]);
932
1
                    break;
933
1
                case Fragment::OR_I:
934
1
                    if (node.subs[0].fragment == Fragment::JUST_0) return "l" + std::move(subs[1]);
935
1
                    if (node.subs[1].fragment == Fragment::JUST_0) return "u" + std::move(subs[0]);
936
1
                    break;
937
1
                default: break;
938
1
            }
939
1
            switch (node.fragment) {
940
1
                case Fragment::PK_K: {
941
1
                    auto key_str = toString(node.keys[0]);
942
1
                    if (!key_str) return {};
943
1
                    return std::move(ret) + "pk_k(" + std::move(*key_str) + ")";
944
1
                }
945
1
                case Fragment::PK_H: {
946
1
                    auto key_str = toString(node.keys[0]);
947
1
                    if (!key_str) return {};
948
1
                    return std::move(ret) + "pk_h(" + std::move(*key_str) + ")";
949
1
                }
950
1
                case Fragment::AFTER: return std::move(ret) + "after(" + util::ToString(node.k) + ")";
951
1
                case Fragment::OLDER: return std::move(ret) + "older(" + util::ToString(node.k) + ")";
952
1
                case Fragment::HASH256: return std::move(ret) + "hash256(" + HexStr(node.data) + ")";
953
1
                case Fragment::HASH160: return std::move(ret) + "hash160(" + HexStr(node.data) + ")";
954
1
                case Fragment::SHA256: return std::move(ret) + "sha256(" + HexStr(node.data) + ")";
955
1
                case Fragment::RIPEMD160: return std::move(ret) + "ripemd160(" + HexStr(node.data) + ")";
956
1
                case Fragment::JUST_1: return std::move(ret) + "1";
957
1
                case Fragment::JUST_0: return std::move(ret) + "0";
958
1
                case Fragment::AND_V: return std::move(ret) + "and_v(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
959
1
                case Fragment::AND_B: return std::move(ret) + "and_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
960
1
                case Fragment::OR_B: return std::move(ret) + "or_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
961
1
                case Fragment::OR_D: return std::move(ret) + "or_d(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
962
1
                case Fragment::OR_C: return std::move(ret) + "or_c(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
963
1
                case Fragment::OR_I: return std::move(ret) + "or_i(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
964
1
                case Fragment::ANDOR:
965
                    // and_n(X,Y) is syntactic sugar for andor(X,Y,0).
966
1
                    if (node.subs[2].fragment == Fragment::JUST_0) return std::move(ret) + "and_n(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
967
1
                    return std::move(ret) + "andor(" + std::move(subs[0]) + "," + std::move(subs[1]) + "," + std::move(subs[2]) + ")";
968
1
                case Fragment::MULTI: {
969
1
                    CHECK_NONFATAL(!is_tapscript);
970
1
                    auto str = std::move(ret) + "multi(" + util::ToString(node.k);
971
1
                    for (const auto& key : node.keys) {
972
1
                        auto key_str = toString(key);
973
1
                        if (!key_str) return {};
974
1
                        str += "," + std::move(*key_str);
975
1
                    }
976
1
                    return std::move(str) + ")";
977
1
                }
978
1
                case Fragment::MULTI_A: {
979
1
                    CHECK_NONFATAL(is_tapscript);
980
1
                    auto str = std::move(ret) + "multi_a(" + util::ToString(node.k);
981
1
                    for (const auto& key : node.keys) {
982
1
                        auto key_str = toString(key);
983
1
                        if (!key_str) return {};
984
1
                        str += "," + std::move(*key_str);
985
1
                    }
986
1
                    return std::move(str) + ")";
987
1
                }
988
1
                case Fragment::THRESH: {
989
1
                    auto str = std::move(ret) + "thresh(" + util::ToString(node.k);
990
1
                    for (auto& sub : subs) {
991
1
                        str += "," + std::move(sub);
992
1
                    }
993
1
                    return std::move(str) + ")";
994
1
                }
995
1
                default: break;
996
1
            }
997
1
            assert(false);
998
1
        };
999
1000
1
        return TreeEvalMaybe<std::string>(false, downfn, upfn);
1001
1
    }
descriptor.cpp:std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<unsigned int>::ToString<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&, bool&) const
Line
Count
Source
883
14
    std::optional<std::string> ToString(const CTx& ctx, bool& has_priv_key) const {
884
        // To construct the std::string representation for a Miniscript object, we use
885
        // the TreeEvalMaybe algorithm. The State is a boolean: whether the parent node is a
886
        // wrapper. If so, non-wrapper expressions must be prefixed with a ":".
887
14
        auto downfn = [](bool, const Node& node, size_t) {
888
14
            return (node.fragment == Fragment::WRAP_A || node.fragment == Fragment::WRAP_S ||
889
14
                    node.fragment == Fragment::WRAP_D || node.fragment == Fragment::WRAP_V ||
890
14
                    node.fragment == Fragment::WRAP_J || node.fragment == Fragment::WRAP_N ||
891
14
                    node.fragment == Fragment::WRAP_C ||
892
14
                    (node.fragment == Fragment::AND_V && node.subs[1].fragment == Fragment::JUST_1) ||
893
14
                    (node.fragment == Fragment::OR_I && node.subs[0].fragment == Fragment::JUST_0) ||
894
14
                    (node.fragment == Fragment::OR_I && node.subs[1].fragment == Fragment::JUST_0));
895
14
        };
896
14
        auto toString = [&ctx, &has_priv_key](Key key) -> std::optional<std::string> {
897
14
            bool fragment_has_priv_key{false};
898
14
            auto key_str{ctx.ToString(key, fragment_has_priv_key)};
899
14
            if (key_str) has_priv_key = has_priv_key || fragment_has_priv_key;
900
14
            return key_str;
901
14
        };
902
        // The upward function computes for a node, given whether its parent is a wrapper,
903
        // and the string representations of its child nodes, the string representation of the node.
904
14
        const bool is_tapscript{IsTapscript(m_script_ctx)};
905
14
        auto upfn = [is_tapscript, &toString](bool wrapped, const Node& node, std::span<std::string> subs) -> std::optional<std::string> {
906
14
            std::string ret = wrapped ? ":" : "";
907
908
14
            switch (node.fragment) {
909
14
                case Fragment::WRAP_A: return "a" + std::move(subs[0]);
910
14
                case Fragment::WRAP_S: return "s" + std::move(subs[0]);
911
14
                case Fragment::WRAP_C:
912
14
                    if (node.subs[0].fragment == Fragment::PK_K) {
913
                        // pk(K) is syntactic sugar for c:pk_k(K)
914
14
                        auto key_str = toString(node.subs[0].keys[0]);
915
14
                        if (!key_str) return {};
916
14
                        return std::move(ret) + "pk(" + std::move(*key_str) + ")";
917
14
                    }
918
14
                    if (node.subs[0].fragment == Fragment::PK_H) {
919
                        // pkh(K) is syntactic sugar for c:pk_h(K)
920
14
                        auto key_str = toString(node.subs[0].keys[0]);
921
14
                        if (!key_str) return {};
922
14
                        return std::move(ret) + "pkh(" + std::move(*key_str) + ")";
923
14
                    }
924
14
                    return "c" + std::move(subs[0]);
925
14
                case Fragment::WRAP_D: return "d" + std::move(subs[0]);
926
14
                case Fragment::WRAP_V: return "v" + std::move(subs[0]);
927
14
                case Fragment::WRAP_J: return "j" + std::move(subs[0]);
928
14
                case Fragment::WRAP_N: return "n" + std::move(subs[0]);
929
14
                case Fragment::AND_V:
930
                    // t:X is syntactic sugar for and_v(X,1).
931
14
                    if (node.subs[1].fragment == Fragment::JUST_1) return "t" + std::move(subs[0]);
932
14
                    break;
933
14
                case Fragment::OR_I:
934
14
                    if (node.subs[0].fragment == Fragment::JUST_0) return "l" + std::move(subs[1]);
935
14
                    if (node.subs[1].fragment == Fragment::JUST_0) return "u" + std::move(subs[0]);
936
14
                    break;
937
14
                default: break;
938
14
            }
939
14
            switch (node.fragment) {
940
14
                case Fragment::PK_K: {
941
14
                    auto key_str = toString(node.keys[0]);
942
14
                    if (!key_str) return {};
943
14
                    return std::move(ret) + "pk_k(" + std::move(*key_str) + ")";
944
14
                }
945
14
                case Fragment::PK_H: {
946
14
                    auto key_str = toString(node.keys[0]);
947
14
                    if (!key_str) return {};
948
14
                    return std::move(ret) + "pk_h(" + std::move(*key_str) + ")";
949
14
                }
950
14
                case Fragment::AFTER: return std::move(ret) + "after(" + util::ToString(node.k) + ")";
951
14
                case Fragment::OLDER: return std::move(ret) + "older(" + util::ToString(node.k) + ")";
952
14
                case Fragment::HASH256: return std::move(ret) + "hash256(" + HexStr(node.data) + ")";
953
14
                case Fragment::HASH160: return std::move(ret) + "hash160(" + HexStr(node.data) + ")";
954
14
                case Fragment::SHA256: return std::move(ret) + "sha256(" + HexStr(node.data) + ")";
955
14
                case Fragment::RIPEMD160: return std::move(ret) + "ripemd160(" + HexStr(node.data) + ")";
956
14
                case Fragment::JUST_1: return std::move(ret) + "1";
957
14
                case Fragment::JUST_0: return std::move(ret) + "0";
958
14
                case Fragment::AND_V: return std::move(ret) + "and_v(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
959
14
                case Fragment::AND_B: return std::move(ret) + "and_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
960
14
                case Fragment::OR_B: return std::move(ret) + "or_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
961
14
                case Fragment::OR_D: return std::move(ret) + "or_d(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
962
14
                case Fragment::OR_C: return std::move(ret) + "or_c(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
963
14
                case Fragment::OR_I: return std::move(ret) + "or_i(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
964
14
                case Fragment::ANDOR:
965
                    // and_n(X,Y) is syntactic sugar for andor(X,Y,0).
966
14
                    if (node.subs[2].fragment == Fragment::JUST_0) return std::move(ret) + "and_n(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
967
14
                    return std::move(ret) + "andor(" + std::move(subs[0]) + "," + std::move(subs[1]) + "," + std::move(subs[2]) + ")";
968
14
                case Fragment::MULTI: {
969
14
                    CHECK_NONFATAL(!is_tapscript);
970
14
                    auto str = std::move(ret) + "multi(" + util::ToString(node.k);
971
14
                    for (const auto& key : node.keys) {
972
14
                        auto key_str = toString(key);
973
14
                        if (!key_str) return {};
974
14
                        str += "," + std::move(*key_str);
975
14
                    }
976
14
                    return std::move(str) + ")";
977
14
                }
978
14
                case Fragment::MULTI_A: {
979
14
                    CHECK_NONFATAL(is_tapscript);
980
14
                    auto str = std::move(ret) + "multi_a(" + util::ToString(node.k);
981
14
                    for (const auto& key : node.keys) {
982
14
                        auto key_str = toString(key);
983
14
                        if (!key_str) return {};
984
14
                        str += "," + std::move(*key_str);
985
14
                    }
986
14
                    return std::move(str) + ")";
987
14
                }
988
14
                case Fragment::THRESH: {
989
14
                    auto str = std::move(ret) + "thresh(" + util::ToString(node.k);
990
14
                    for (auto& sub : subs) {
991
14
                        str += "," + std::move(sub);
992
14
                    }
993
14
                    return std::move(str) + ")";
994
14
                }
995
14
                default: break;
996
14
            }
997
14
            assert(false);
998
14
        };
999
1000
14
        return TreeEvalMaybe<std::string>(false, downfn, upfn);
1001
14
    }
descriptor.cpp:std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>> miniscript::Node<unsigned int>::ToString<(anonymous namespace)::StringMaker>((anonymous namespace)::StringMaker const&, bool&) const
Line
Count
Source
883
1.10k
    std::optional<std::string> ToString(const CTx& ctx, bool& has_priv_key) const {
884
        // To construct the std::string representation for a Miniscript object, we use
885
        // the TreeEvalMaybe algorithm. The State is a boolean: whether the parent node is a
886
        // wrapper. If so, non-wrapper expressions must be prefixed with a ":".
887
1.10k
        auto downfn = [](bool, const Node& node, size_t) {
888
1.10k
            return (node.fragment == Fragment::WRAP_A || node.fragment == Fragment::WRAP_S ||
889
1.10k
                    node.fragment == Fragment::WRAP_D || node.fragment == Fragment::WRAP_V ||
890
1.10k
                    node.fragment == Fragment::WRAP_J || node.fragment == Fragment::WRAP_N ||
891
1.10k
                    node.fragment == Fragment::WRAP_C ||
892
1.10k
                    (node.fragment == Fragment::AND_V && node.subs[1].fragment == Fragment::JUST_1) ||
893
1.10k
                    (node.fragment == Fragment::OR_I && node.subs[0].fragment == Fragment::JUST_0) ||
894
1.10k
                    (node.fragment == Fragment::OR_I && node.subs[1].fragment == Fragment::JUST_0));
895
1.10k
        };
896
1.10k
        auto toString = [&ctx, &has_priv_key](Key key) -> std::optional<std::string> {
897
1.10k
            bool fragment_has_priv_key{false};
898
1.10k
            auto key_str{ctx.ToString(key, fragment_has_priv_key)};
899
1.10k
            if (key_str) has_priv_key = has_priv_key || fragment_has_priv_key;
900
1.10k
            return key_str;
901
1.10k
        };
902
        // The upward function computes for a node, given whether its parent is a wrapper,
903
        // and the string representations of its child nodes, the string representation of the node.
904
1.10k
        const bool is_tapscript{IsTapscript(m_script_ctx)};
905
1.10k
        auto upfn = [is_tapscript, &toString](bool wrapped, const Node& node, std::span<std::string> subs) -> std::optional<std::string> {
906
1.10k
            std::string ret = wrapped ? ":" : "";
907
908
1.10k
            switch (node.fragment) {
909
1.10k
                case Fragment::WRAP_A: return "a" + std::move(subs[0]);
910
1.10k
                case Fragment::WRAP_S: return "s" + std::move(subs[0]);
911
1.10k
                case Fragment::WRAP_C:
912
1.10k
                    if (node.subs[0].fragment == Fragment::PK_K) {
913
                        // pk(K) is syntactic sugar for c:pk_k(K)
914
1.10k
                        auto key_str = toString(node.subs[0].keys[0]);
915
1.10k
                        if (!key_str) return {};
916
1.10k
                        return std::move(ret) + "pk(" + std::move(*key_str) + ")";
917
1.10k
                    }
918
1.10k
                    if (node.subs[0].fragment == Fragment::PK_H) {
919
                        // pkh(K) is syntactic sugar for c:pk_h(K)
920
1.10k
                        auto key_str = toString(node.subs[0].keys[0]);
921
1.10k
                        if (!key_str) return {};
922
1.10k
                        return std::move(ret) + "pkh(" + std::move(*key_str) + ")";
923
1.10k
                    }
924
1.10k
                    return "c" + std::move(subs[0]);
925
1.10k
                case Fragment::WRAP_D: return "d" + std::move(subs[0]);
926
1.10k
                case Fragment::WRAP_V: return "v" + std::move(subs[0]);
927
1.10k
                case Fragment::WRAP_J: return "j" + std::move(subs[0]);
928
1.10k
                case Fragment::WRAP_N: return "n" + std::move(subs[0]);
929
1.10k
                case Fragment::AND_V:
930
                    // t:X is syntactic sugar for and_v(X,1).
931
1.10k
                    if (node.subs[1].fragment == Fragment::JUST_1) return "t" + std::move(subs[0]);
932
1.10k
                    break;
933
1.10k
                case Fragment::OR_I:
934
1.10k
                    if (node.subs[0].fragment == Fragment::JUST_0) return "l" + std::move(subs[1]);
935
1.10k
                    if (node.subs[1].fragment == Fragment::JUST_0) return "u" + std::move(subs[0]);
936
1.10k
                    break;
937
1.10k
                default: break;
938
1.10k
            }
939
1.10k
            switch (node.fragment) {
940
1.10k
                case Fragment::PK_K: {
941
1.10k
                    auto key_str = toString(node.keys[0]);
942
1.10k
                    if (!key_str) return {};
943
1.10k
                    return std::move(ret) + "pk_k(" + std::move(*key_str) + ")";
944
1.10k
                }
945
1.10k
                case Fragment::PK_H: {
946
1.10k
                    auto key_str = toString(node.keys[0]);
947
1.10k
                    if (!key_str) return {};
948
1.10k
                    return std::move(ret) + "pk_h(" + std::move(*key_str) + ")";
949
1.10k
                }
950
1.10k
                case Fragment::AFTER: return std::move(ret) + "after(" + util::ToString(node.k) + ")";
951
1.10k
                case Fragment::OLDER: return std::move(ret) + "older(" + util::ToString(node.k) + ")";
952
1.10k
                case Fragment::HASH256: return std::move(ret) + "hash256(" + HexStr(node.data) + ")";
953
1.10k
                case Fragment::HASH160: return std::move(ret) + "hash160(" + HexStr(node.data) + ")";
954
1.10k
                case Fragment::SHA256: return std::move(ret) + "sha256(" + HexStr(node.data) + ")";
955
1.10k
                case Fragment::RIPEMD160: return std::move(ret) + "ripemd160(" + HexStr(node.data) + ")";
956
1.10k
                case Fragment::JUST_1: return std::move(ret) + "1";
957
1.10k
                case Fragment::JUST_0: return std::move(ret) + "0";
958
1.10k
                case Fragment::AND_V: return std::move(ret) + "and_v(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
959
1.10k
                case Fragment::AND_B: return std::move(ret) + "and_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
960
1.10k
                case Fragment::OR_B: return std::move(ret) + "or_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
961
1.10k
                case Fragment::OR_D: return std::move(ret) + "or_d(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
962
1.10k
                case Fragment::OR_C: return std::move(ret) + "or_c(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
963
1.10k
                case Fragment::OR_I: return std::move(ret) + "or_i(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
964
1.10k
                case Fragment::ANDOR:
965
                    // and_n(X,Y) is syntactic sugar for andor(X,Y,0).
966
1.10k
                    if (node.subs[2].fragment == Fragment::JUST_0) return std::move(ret) + "and_n(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
967
1.10k
                    return std::move(ret) + "andor(" + std::move(subs[0]) + "," + std::move(subs[1]) + "," + std::move(subs[2]) + ")";
968
1.10k
                case Fragment::MULTI: {
969
1.10k
                    CHECK_NONFATAL(!is_tapscript);
970
1.10k
                    auto str = std::move(ret) + "multi(" + util::ToString(node.k);
971
1.10k
                    for (const auto& key : node.keys) {
972
1.10k
                        auto key_str = toString(key);
973
1.10k
                        if (!key_str) return {};
974
1.10k
                        str += "," + std::move(*key_str);
975
1.10k
                    }
976
1.10k
                    return std::move(str) + ")";
977
1.10k
                }
978
1.10k
                case Fragment::MULTI_A: {
979
1.10k
                    CHECK_NONFATAL(is_tapscript);
980
1.10k
                    auto str = std::move(ret) + "multi_a(" + util::ToString(node.k);
981
1.10k
                    for (const auto& key : node.keys) {
982
1.10k
                        auto key_str = toString(key);
983
1.10k
                        if (!key_str) return {};
984
1.10k
                        str += "," + std::move(*key_str);
985
1.10k
                    }
986
1.10k
                    return std::move(str) + ")";
987
1.10k
                }
988
1.10k
                case Fragment::THRESH: {
989
1.10k
                    auto str = std::move(ret) + "thresh(" + util::ToString(node.k);
990
1.10k
                    for (auto& sub : subs) {
991
1.10k
                        str += "," + std::move(sub);
992
1.10k
                    }
993
1.10k
                    return std::move(str) + ")";
994
1.10k
                }
995
1.10k
                default: break;
996
1.10k
            }
997
1.10k
            assert(false);
998
1.10k
        };
999
1000
1.10k
        return TreeEvalMaybe<std::string>(false, downfn, upfn);
1001
1.10k
    }
1002
1003
private:
1004
3.74M
    internal::Ops CalcOps() const {
1005
3.74M
        switch (fragment) {
1006
245
            case Fragment::JUST_1: return {0, 0, {}};
1007
709
            case Fragment::JUST_0: return {0, {}, 0};
1008
6.51k
            case Fragment::PK_K: return {0, 0, 0};
1009
934
            case Fragment::PK_H: return {3, 0, 0};
1010
7.94k
            case Fragment::OLDER:
1011
9.45k
            case Fragment::AFTER: return {1, 0, {}};
1012
102
            case Fragment::SHA256:
1013
179
            case Fragment::RIPEMD160:
1014
295
            case Fragment::HASH256:
1015
392
            case Fragment::HASH160: return {4, 0, {}};
1016
1.85k
            case Fragment::AND_V: return {subs[0].ops.count + subs[1].ops.count, subs[0].ops.sat + subs[1].ops.sat, {}};
1017
7.19k
            case Fragment::AND_B: {
1018
7.19k
                const auto count{1 + subs[0].ops.count + subs[1].ops.count};
1019
7.19k
                const auto sat{subs[0].ops.sat + subs[1].ops.sat};
1020
7.19k
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1021
7.19k
                return {count, sat, dsat};
1022
295
            }
1023
127
            case Fragment::OR_B: {
1024
127
                const auto count{1 + subs[0].ops.count + subs[1].ops.count};
1025
127
                const auto sat{(subs[0].ops.sat + subs[1].ops.dsat) | (subs[1].ops.sat + subs[0].ops.dsat)};
1026
127
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1027
127
                return {count, sat, dsat};
1028
295
            }
1029
127
            case Fragment::OR_D: {
1030
127
                const auto count{3 + subs[0].ops.count + subs[1].ops.count};
1031
127
                const auto sat{subs[0].ops.sat | (subs[1].ops.sat + subs[0].ops.dsat)};
1032
127
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1033
127
                return {count, sat, dsat};
1034
295
            }
1035
60
            case Fragment::OR_C: {
1036
60
                const auto count{2 + subs[0].ops.count + subs[1].ops.count};
1037
60
                const auto sat{subs[0].ops.sat | (subs[1].ops.sat + subs[0].ops.dsat)};
1038
60
                return {count, sat, {}};
1039
295
            }
1040
652
            case Fragment::OR_I: {
1041
652
                const auto count{3 + subs[0].ops.count + subs[1].ops.count};
1042
652
                const auto sat{subs[0].ops.sat | subs[1].ops.sat};
1043
652
                const auto dsat{subs[0].ops.dsat | subs[1].ops.dsat};
1044
652
                return {count, sat, dsat};
1045
295
            }
1046
240
            case Fragment::ANDOR: {
1047
240
                const auto count{3 + subs[0].ops.count + subs[1].ops.count + subs[2].ops.count};
1048
240
                const auto sat{(subs[1].ops.sat + subs[0].ops.sat) | (subs[0].ops.dsat + subs[2].ops.sat)};
1049
240
                const auto dsat{subs[0].ops.dsat + subs[2].ops.dsat};
1050
240
                return {count, sat, dsat};
1051
295
            }
1052
173
            case Fragment::MULTI: return {1, (uint32_t)keys.size(), (uint32_t)keys.size()};
1053
821
            case Fragment::MULTI_A: return {(uint32_t)keys.size() + 1, 0, 0};
1054
922
            case Fragment::WRAP_S:
1055
8.30k
            case Fragment::WRAP_C:
1056
3.70M
            case Fragment::WRAP_N: return {1 + subs[0].ops.count, subs[0].ops.sat, subs[0].ops.dsat};
1057
7.58k
            case Fragment::WRAP_A: return {2 + subs[0].ops.count, subs[0].ops.sat, subs[0].ops.dsat};
1058
114
            case Fragment::WRAP_D: return {3 + subs[0].ops.count, subs[0].ops.sat, 0};
1059
16
            case Fragment::WRAP_J: return {4 + subs[0].ops.count, subs[0].ops.sat, 0};
1060
1.99k
            case Fragment::WRAP_V: return {subs[0].ops.count + (subs[0].GetType() << "x"_mst), subs[0].ops.sat, {}};
1061
411
            case Fragment::THRESH: {
1062
411
                uint32_t count = 0;
1063
411
                auto sats = Vector(internal::MaxInt<uint32_t>(0));
1064
1.58k
                for (const auto& sub : subs) {
1065
1.58k
                    count += sub.ops.count + 1;
1066
1.58k
                    auto next_sats = Vector(sats[0] + sub.ops.dsat);
1067
4.65k
                    for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub.ops.dsat) | (sats[j - 1] + sub.ops.sat));
1068
1.58k
                    next_sats.push_back(sats[sats.size() - 1] + sub.ops.sat);
1069
1.58k
                    sats = std::move(next_sats);
1070
1.58k
                }
1071
411
                assert(k < sats.size());
1072
411
                return {count, sats[k], sats[0]};
1073
411
            }
1074
3.74M
        }
1075
3.74M
        assert(false);
1076
0
    }
miniscript::Node<CPubKey>::CalcOps() const
Line
Count
Source
1004
28.4k
    internal::Ops CalcOps() const {
1005
28.4k
        switch (fragment) {
1006
232
            case Fragment::JUST_1: return {0, 0, {}};
1007
449
            case Fragment::JUST_0: return {0, {}, 0};
1008
1.67k
            case Fragment::PK_K: return {0, 0, 0};
1009
123
            case Fragment::PK_H: return {3, 0, 0};
1010
7.57k
            case Fragment::OLDER:
1011
7.95k
            case Fragment::AFTER: return {1, 0, {}};
1012
60
            case Fragment::SHA256:
1013
86
            case Fragment::RIPEMD160:
1014
126
            case Fragment::HASH256:
1015
150
            case Fragment::HASH160: return {4, 0, {}};
1016
249
            case Fragment::AND_V: return {subs[0].ops.count + subs[1].ops.count, subs[0].ops.sat + subs[1].ops.sat, {}};
1017
6.88k
            case Fragment::AND_B: {
1018
6.88k
                const auto count{1 + subs[0].ops.count + subs[1].ops.count};
1019
6.88k
                const auto sat{subs[0].ops.sat + subs[1].ops.sat};
1020
6.88k
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1021
6.88k
                return {count, sat, dsat};
1022
126
            }
1023
29
            case Fragment::OR_B: {
1024
29
                const auto count{1 + subs[0].ops.count + subs[1].ops.count};
1025
29
                const auto sat{(subs[0].ops.sat + subs[1].ops.dsat) | (subs[1].ops.sat + subs[0].ops.dsat)};
1026
29
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1027
29
                return {count, sat, dsat};
1028
126
            }
1029
43
            case Fragment::OR_D: {
1030
43
                const auto count{3 + subs[0].ops.count + subs[1].ops.count};
1031
43
                const auto sat{subs[0].ops.sat | (subs[1].ops.sat + subs[0].ops.dsat)};
1032
43
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1033
43
                return {count, sat, dsat};
1034
126
            }
1035
20
            case Fragment::OR_C: {
1036
20
                const auto count{2 + subs[0].ops.count + subs[1].ops.count};
1037
20
                const auto sat{subs[0].ops.sat | (subs[1].ops.sat + subs[0].ops.dsat)};
1038
20
                return {count, sat, {}};
1039
126
            }
1040
398
            case Fragment::OR_I: {
1041
398
                const auto count{3 + subs[0].ops.count + subs[1].ops.count};
1042
398
                const auto sat{subs[0].ops.sat | subs[1].ops.sat};
1043
398
                const auto dsat{subs[0].ops.dsat | subs[1].ops.dsat};
1044
398
                return {count, sat, dsat};
1045
126
            }
1046
104
            case Fragment::ANDOR: {
1047
104
                const auto count{3 + subs[0].ops.count + subs[1].ops.count + subs[2].ops.count};
1048
104
                const auto sat{(subs[1].ops.sat + subs[0].ops.sat) | (subs[0].ops.dsat + subs[2].ops.sat)};
1049
104
                const auto dsat{subs[0].ops.dsat + subs[2].ops.dsat};
1050
104
                return {count, sat, dsat};
1051
126
            }
1052
49
            case Fragment::MULTI: return {1, (uint32_t)keys.size(), (uint32_t)keys.size()};
1053
5
            case Fragment::MULTI_A: return {(uint32_t)keys.size() + 1, 0, 0};
1054
478
            case Fragment::WRAP_S:
1055
2.23k
            case Fragment::WRAP_C:
1056
2.53k
            case Fragment::WRAP_N: return {1 + subs[0].ops.count, subs[0].ops.sat, subs[0].ops.dsat};
1057
7.00k
            case Fragment::WRAP_A: return {2 + subs[0].ops.count, subs[0].ops.sat, subs[0].ops.dsat};
1058
36
            case Fragment::WRAP_D: return {3 + subs[0].ops.count, subs[0].ops.sat, 0};
1059
16
            case Fragment::WRAP_J: return {4 + subs[0].ops.count, subs[0].ops.sat, 0};
1060
305
            case Fragment::WRAP_V: return {subs[0].ops.count + (subs[0].GetType() << "x"_mst), subs[0].ops.sat, {}};
1061
147
            case Fragment::THRESH: {
1062
147
                uint32_t count = 0;
1063
147
                auto sats = Vector(internal::MaxInt<uint32_t>(0));
1064
700
                for (const auto& sub : subs) {
1065
700
                    count += sub.ops.count + 1;
1066
700
                    auto next_sats = Vector(sats[0] + sub.ops.dsat);
1067
2.39k
                    for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub.ops.dsat) | (sats[j - 1] + sub.ops.sat));
1068
700
                    next_sats.push_back(sats[sats.size() - 1] + sub.ops.sat);
1069
700
                    sats = std::move(next_sats);
1070
700
                }
1071
147
                assert(k < sats.size());
1072
147
                return {count, sats[k], sats[0]};
1073
147
            }
1074
28.4k
        }
1075
28.4k
        assert(false);
1076
0
    }
miniscript::Node<unsigned int>::CalcOps() const
Line
Count
Source
1004
1.72M
    internal::Ops CalcOps() const {
1005
1.72M
        switch (fragment) {
1006
13
            case Fragment::JUST_1: return {0, 0, {}};
1007
260
            case Fragment::JUST_0: return {0, {}, 0};
1008
1.46k
            case Fragment::PK_K: return {0, 0, 0};
1009
475
            case Fragment::PK_H: return {3, 0, 0};
1010
322
            case Fragment::OLDER:
1011
661
            case Fragment::AFTER: return {1, 0, {}};
1012
42
            case Fragment::SHA256:
1013
93
            case Fragment::RIPEMD160:
1014
157
            case Fragment::HASH256:
1015
230
            case Fragment::HASH160: return {4, 0, {}};
1016
724
            case Fragment::AND_V: return {subs[0].ops.count + subs[1].ops.count, subs[0].ops.sat + subs[1].ops.sat, {}};
1017
249
            case Fragment::AND_B: {
1018
249
                const auto count{1 + subs[0].ops.count + subs[1].ops.count};
1019
249
                const auto sat{subs[0].ops.sat + subs[1].ops.sat};
1020
249
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1021
249
                return {count, sat, dsat};
1022
157
            }
1023
70
            case Fragment::OR_B: {
1024
70
                const auto count{1 + subs[0].ops.count + subs[1].ops.count};
1025
70
                const auto sat{(subs[0].ops.sat + subs[1].ops.dsat) | (subs[1].ops.sat + subs[0].ops.dsat)};
1026
70
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1027
70
                return {count, sat, dsat};
1028
157
            }
1029
84
            case Fragment::OR_D: {
1030
84
                const auto count{3 + subs[0].ops.count + subs[1].ops.count};
1031
84
                const auto sat{subs[0].ops.sat | (subs[1].ops.sat + subs[0].ops.dsat)};
1032
84
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1033
84
                return {count, sat, dsat};
1034
157
            }
1035
40
            case Fragment::OR_C: {
1036
40
                const auto count{2 + subs[0].ops.count + subs[1].ops.count};
1037
40
                const auto sat{subs[0].ops.sat | (subs[1].ops.sat + subs[0].ops.dsat)};
1038
40
                return {count, sat, {}};
1039
157
            }
1040
254
            case Fragment::OR_I: {
1041
254
                const auto count{3 + subs[0].ops.count + subs[1].ops.count};
1042
254
                const auto sat{subs[0].ops.sat | subs[1].ops.sat};
1043
254
                const auto dsat{subs[0].ops.dsat | subs[1].ops.dsat};
1044
254
                return {count, sat, dsat};
1045
157
            }
1046
136
            case Fragment::ANDOR: {
1047
136
                const auto count{3 + subs[0].ops.count + subs[1].ops.count + subs[2].ops.count};
1048
136
                const auto sat{(subs[1].ops.sat + subs[0].ops.sat) | (subs[0].ops.dsat + subs[2].ops.sat)};
1049
136
                const auto dsat{subs[0].ops.dsat + subs[2].ops.dsat};
1050
136
                return {count, sat, dsat};
1051
157
            }
1052
124
            case Fragment::MULTI: return {1, (uint32_t)keys.size(), (uint32_t)keys.size()};
1053
32
            case Fragment::MULTI_A: return {(uint32_t)keys.size() + 1, 0, 0};
1054
394
            case Fragment::WRAP_S:
1055
2.30k
            case Fragment::WRAP_C:
1056
1.72M
            case Fragment::WRAP_N: return {1 + subs[0].ops.count, subs[0].ops.sat, subs[0].ops.dsat};
1057
495
            case Fragment::WRAP_A: return {2 + subs[0].ops.count, subs[0].ops.sat, subs[0].ops.dsat};
1058
72
            case Fragment::WRAP_D: return {3 + subs[0].ops.count, subs[0].ops.sat, 0};
1059
0
            case Fragment::WRAP_J: return {4 + subs[0].ops.count, subs[0].ops.sat, 0};
1060
801
            case Fragment::WRAP_V: return {subs[0].ops.count + (subs[0].GetType() << "x"_mst), subs[0].ops.sat, {}};
1061
242
            case Fragment::THRESH: {
1062
242
                uint32_t count = 0;
1063
242
                auto sats = Vector(internal::MaxInt<uint32_t>(0));
1064
814
                for (const auto& sub : subs) {
1065
814
                    count += sub.ops.count + 1;
1066
814
                    auto next_sats = Vector(sats[0] + sub.ops.dsat);
1067
2.12k
                    for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub.ops.dsat) | (sats[j - 1] + sub.ops.sat));
1068
814
                    next_sats.push_back(sats[sats.size() - 1] + sub.ops.sat);
1069
814
                    sats = std::move(next_sats);
1070
814
                }
1071
242
                assert(k < sats.size());
1072
242
                return {count, sats[k], sats[0]};
1073
242
            }
1074
1.72M
        }
1075
1.72M
        assert(false);
1076
0
    }
miniscript::Node<XOnlyPubKey>::CalcOps() const
Line
Count
Source
1004
1.98M
    internal::Ops CalcOps() const {
1005
1.98M
        switch (fragment) {
1006
0
            case Fragment::JUST_1: return {0, 0, {}};
1007
0
            case Fragment::JUST_0: return {0, {}, 0};
1008
3.37k
            case Fragment::PK_K: return {0, 0, 0};
1009
336
            case Fragment::PK_H: return {3, 0, 0};
1010
51
            case Fragment::OLDER:
1011
840
            case Fragment::AFTER: return {1, 0, {}};
1012
0
            case Fragment::SHA256:
1013
0
            case Fragment::RIPEMD160:
1014
12
            case Fragment::HASH256:
1015
12
            case Fragment::HASH160: return {4, 0, {}};
1016
880
            case Fragment::AND_V: return {subs[0].ops.count + subs[1].ops.count, subs[0].ops.sat + subs[1].ops.sat, {}};
1017
64
            case Fragment::AND_B: {
1018
64
                const auto count{1 + subs[0].ops.count + subs[1].ops.count};
1019
64
                const auto sat{subs[0].ops.sat + subs[1].ops.sat};
1020
64
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1021
64
                return {count, sat, dsat};
1022
12
            }
1023
28
            case Fragment::OR_B: {
1024
28
                const auto count{1 + subs[0].ops.count + subs[1].ops.count};
1025
28
                const auto sat{(subs[0].ops.sat + subs[1].ops.dsat) | (subs[1].ops.sat + subs[0].ops.dsat)};
1026
28
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1027
28
                return {count, sat, dsat};
1028
12
            }
1029
0
            case Fragment::OR_D: {
1030
0
                const auto count{3 + subs[0].ops.count + subs[1].ops.count};
1031
0
                const auto sat{subs[0].ops.sat | (subs[1].ops.sat + subs[0].ops.dsat)};
1032
0
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1033
0
                return {count, sat, dsat};
1034
12
            }
1035
0
            case Fragment::OR_C: {
1036
0
                const auto count{2 + subs[0].ops.count + subs[1].ops.count};
1037
0
                const auto sat{subs[0].ops.sat | (subs[1].ops.sat + subs[0].ops.dsat)};
1038
0
                return {count, sat, {}};
1039
12
            }
1040
0
            case Fragment::OR_I: {
1041
0
                const auto count{3 + subs[0].ops.count + subs[1].ops.count};
1042
0
                const auto sat{subs[0].ops.sat | subs[1].ops.sat};
1043
0
                const auto dsat{subs[0].ops.dsat | subs[1].ops.dsat};
1044
0
                return {count, sat, dsat};
1045
12
            }
1046
0
            case Fragment::ANDOR: {
1047
0
                const auto count{3 + subs[0].ops.count + subs[1].ops.count + subs[2].ops.count};
1048
0
                const auto sat{(subs[1].ops.sat + subs[0].ops.sat) | (subs[0].ops.dsat + subs[2].ops.sat)};
1049
0
                const auto dsat{subs[0].ops.dsat + subs[2].ops.dsat};
1050
0
                return {count, sat, dsat};
1051
12
            }
1052
0
            case Fragment::MULTI: return {1, (uint32_t)keys.size(), (uint32_t)keys.size()};
1053
784
            case Fragment::MULTI_A: return {(uint32_t)keys.size() + 1, 0, 0};
1054
50
            case Fragment::WRAP_S:
1055
3.75k
            case Fragment::WRAP_C:
1056
1.98M
            case Fragment::WRAP_N: return {1 + subs[0].ops.count, subs[0].ops.sat, subs[0].ops.dsat};
1057
86
            case Fragment::WRAP_A: return {2 + subs[0].ops.count, subs[0].ops.sat, subs[0].ops.dsat};
1058
6
            case Fragment::WRAP_D: return {3 + subs[0].ops.count, subs[0].ops.sat, 0};
1059
0
            case Fragment::WRAP_J: return {4 + subs[0].ops.count, subs[0].ops.sat, 0};
1060
886
            case Fragment::WRAP_V: return {subs[0].ops.count + (subs[0].GetType() << "x"_mst), subs[0].ops.sat, {}};
1061
22
            case Fragment::THRESH: {
1062
22
                uint32_t count = 0;
1063
22
                auto sats = Vector(internal::MaxInt<uint32_t>(0));
1064
66
                for (const auto& sub : subs) {
1065
66
                    count += sub.ops.count + 1;
1066
66
                    auto next_sats = Vector(sats[0] + sub.ops.dsat);
1067
132
                    for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub.ops.dsat) | (sats[j - 1] + sub.ops.sat));
1068
66
                    next_sats.push_back(sats[sats.size() - 1] + sub.ops.sat);
1069
66
                    sats = std::move(next_sats);
1070
66
                }
1071
22
                assert(k < sats.size());
1072
22
                return {count, sats[k], sats[0]};
1073
22
            }
1074
1.98M
        }
1075
1.98M
        assert(false);
1076
0
    }
1077
1078
3.74M
    internal::StackSize CalcStackSize() const {
1079
3.74M
        using namespace internal;
1080
3.74M
        switch (fragment) {
1081
709
            case Fragment::JUST_0: return {{}, SatInfo::Push()};
1082
245
            case Fragment::JUST_1: return {SatInfo::Push(), {}};
1083
7.94k
            case Fragment::OLDER:
1084
9.45k
            case Fragment::AFTER: return {SatInfo::Push() + SatInfo::Nop(), {}};
1085
6.51k
            case Fragment::PK_K: return {SatInfo::Push()};
1086
934
            case Fragment::PK_H: return {SatInfo::OP_DUP() + SatInfo::Hash() + SatInfo::Push() + SatInfo::OP_EQUALVERIFY()};
1087
102
            case Fragment::SHA256:
1088
179
            case Fragment::RIPEMD160:
1089
295
            case Fragment::HASH256:
1090
392
            case Fragment::HASH160: return {
1091
392
                SatInfo::OP_SIZE() + SatInfo::Push() + SatInfo::OP_EQUALVERIFY() + SatInfo::Hash() + SatInfo::Push() + SatInfo::OP_EQUAL(),
1092
392
                {}
1093
392
            };
1094
240
            case Fragment::ANDOR: {
1095
240
                const auto& x{subs[0].ss};
1096
240
                const auto& y{subs[1].ss};
1097
240
                const auto& z{subs[2].ss};
1098
240
                return {
1099
240
                    (x.Sat() + SatInfo::If() + y.Sat()) | (x.Dsat() + SatInfo::If() + z.Sat()),
1100
240
                    x.Dsat() + SatInfo::If() + z.Dsat()
1101
240
                };
1102
295
            }
1103
1.85k
            case Fragment::AND_V: {
1104
1.85k
                const auto& x{subs[0].ss};
1105
1.85k
                const auto& y{subs[1].ss};
1106
1.85k
                return {x.Sat() + y.Sat(), {}};
1107
295
            }
1108
7.19k
            case Fragment::AND_B: {
1109
7.19k
                const auto& x{subs[0].ss};
1110
7.19k
                const auto& y{subs[1].ss};
1111
7.19k
                return {x.Sat() + y.Sat() + SatInfo::BinaryOp(), x.Dsat() + y.Dsat() + SatInfo::BinaryOp()};
1112
295
            }
1113
127
            case Fragment::OR_B: {
1114
127
                const auto& x{subs[0].ss};
1115
127
                const auto& y{subs[1].ss};
1116
127
                return {
1117
127
                    ((x.Sat() + y.Dsat()) | (x.Dsat() + y.Sat())) + SatInfo::BinaryOp(),
1118
127
                    x.Dsat() + y.Dsat() + SatInfo::BinaryOp()
1119
127
                };
1120
295
            }
1121
60
            case Fragment::OR_C: {
1122
60
                const auto& x{subs[0].ss};
1123
60
                const auto& y{subs[1].ss};
1124
60
                return {(x.Sat() + SatInfo::If()) | (x.Dsat() + SatInfo::If() + y.Sat()), {}};
1125
295
            }
1126
127
            case Fragment::OR_D: {
1127
127
                const auto& x{subs[0].ss};
1128
127
                const auto& y{subs[1].ss};
1129
127
                return {
1130
127
                    (x.Sat() + SatInfo::OP_IFDUP(true) + SatInfo::If()) | (x.Dsat() + SatInfo::OP_IFDUP(false) + SatInfo::If() + y.Sat()),
1131
127
                    x.Dsat() + SatInfo::OP_IFDUP(false) + SatInfo::If() + y.Dsat()
1132
127
                };
1133
295
            }
1134
652
            case Fragment::OR_I: {
1135
652
                const auto& x{subs[0].ss};
1136
652
                const auto& y{subs[1].ss};
1137
652
                return {SatInfo::If() + (x.Sat() | y.Sat()), SatInfo::If() + (x.Dsat() | y.Dsat())};
1138
295
            }
1139
            // multi(k, key1, key2, ..., key_n) starts off with k+1 stack elements (a 0, plus k
1140
            // signatures), then reaches n+k+3 stack elements after pushing the n keys, plus k and
1141
            // n itself, and ends with 1 stack element (success or failure). Thus, it net removes
1142
            // k elements (from k+1 to 1), while reaching k+n+2 more than it ends with.
1143
173
            case Fragment::MULTI: return {SatInfo(k, k + keys.size() + 2)};
1144
            // multi_a(k, key1, key2, ..., key_n) starts off with n stack elements (the
1145
            // signatures), reaches 1 more (after the first key push), and ends with 1. Thus it net
1146
            // removes n-1 elements (from n to 1) while reaching n more than it ends with.
1147
821
            case Fragment::MULTI_A: return {SatInfo(keys.size() - 1, keys.size())};
1148
7.58k
            case Fragment::WRAP_A:
1149
3.70M
            case Fragment::WRAP_N:
1150
3.70M
            case Fragment::WRAP_S: return subs[0].ss;
1151
7.38k
            case Fragment::WRAP_C: return {
1152
7.38k
                subs[0].ss.Sat() + SatInfo::OP_CHECKSIG(),
1153
7.38k
                subs[0].ss.Dsat() + SatInfo::OP_CHECKSIG()
1154
7.38k
            };
1155
114
            case Fragment::WRAP_D: return {
1156
114
                SatInfo::OP_DUP() + SatInfo::If() + subs[0].ss.Sat(),
1157
114
                SatInfo::OP_DUP() + SatInfo::If()
1158
114
            };
1159
1.99k
            case Fragment::WRAP_V: return {subs[0].ss.Sat() + SatInfo::OP_VERIFY(), {}};
1160
16
            case Fragment::WRAP_J: return {
1161
16
                SatInfo::OP_SIZE() + SatInfo::OP_0NOTEQUAL() + SatInfo::If() + subs[0].ss.Sat(),
1162
16
                SatInfo::OP_SIZE() + SatInfo::OP_0NOTEQUAL() + SatInfo::If()
1163
16
            };
1164
411
            case Fragment::THRESH: {
1165
                // sats[j] is the SatInfo corresponding to all traces reaching j satisfactions.
1166
411
                auto sats = Vector(SatInfo::Empty());
1167
1.99k
                for (size_t i = 0; i < subs.size(); ++i) {
1168
                    // Loop over the subexpressions, processing them one by one. After adding
1169
                    // element i we need to add OP_ADD (if i>0).
1170
1.58k
                    auto add = i ? SatInfo::BinaryOp() : SatInfo::Empty();
1171
                    // Construct a variable that will become the next sats, starting with index 0.
1172
1.58k
                    auto next_sats = Vector(sats[0] + subs[i].ss.Dsat() + add);
1173
                    // Then loop to construct next_sats[1..i].
1174
4.65k
                    for (size_t j = 1; j < sats.size(); ++j) {
1175
3.07k
                        next_sats.push_back(((sats[j] + subs[i].ss.Dsat()) | (sats[j - 1] + subs[i].ss.Sat())) + add);
1176
3.07k
                    }
1177
                    // Finally construct next_sats[i+1].
1178
1.58k
                    next_sats.push_back(sats[sats.size() - 1] + subs[i].ss.Sat() + add);
1179
                    // Switch over.
1180
1.58k
                    sats = std::move(next_sats);
1181
1.58k
                }
1182
                // To satisfy thresh we need k satisfactions; to dissatisfy we need 0. In both
1183
                // cases a push of k and an OP_EQUAL follow.
1184
411
                return {
1185
411
                    sats[k] + SatInfo::Push() + SatInfo::OP_EQUAL(),
1186
411
                    sats[0] + SatInfo::Push() + SatInfo::OP_EQUAL()
1187
411
                };
1188
3.70M
            }
1189
3.74M
        }
1190
3.74M
        assert(false);
1191
0
    }
miniscript::Node<CPubKey>::CalcStackSize() const
Line
Count
Source
1078
28.4k
    internal::StackSize CalcStackSize() const {
1079
28.4k
        using namespace internal;
1080
28.4k
        switch (fragment) {
1081
449
            case Fragment::JUST_0: return {{}, SatInfo::Push()};
1082
232
            case Fragment::JUST_1: return {SatInfo::Push(), {}};
1083
7.57k
            case Fragment::OLDER:
1084
7.95k
            case Fragment::AFTER: return {SatInfo::Push() + SatInfo::Nop(), {}};
1085
1.67k
            case Fragment::PK_K: return {SatInfo::Push()};
1086
123
            case Fragment::PK_H: return {SatInfo::OP_DUP() + SatInfo::Hash() + SatInfo::Push() + SatInfo::OP_EQUALVERIFY()};
1087
60
            case Fragment::SHA256:
1088
86
            case Fragment::RIPEMD160:
1089
126
            case Fragment::HASH256:
1090
150
            case Fragment::HASH160: return {
1091
150
                SatInfo::OP_SIZE() + SatInfo::Push() + SatInfo::OP_EQUALVERIFY() + SatInfo::Hash() + SatInfo::Push() + SatInfo::OP_EQUAL(),
1092
150
                {}
1093
150
            };
1094
104
            case Fragment::ANDOR: {
1095
104
                const auto& x{subs[0].ss};
1096
104
                const auto& y{subs[1].ss};
1097
104
                const auto& z{subs[2].ss};
1098
104
                return {
1099
104
                    (x.Sat() + SatInfo::If() + y.Sat()) | (x.Dsat() + SatInfo::If() + z.Sat()),
1100
104
                    x.Dsat() + SatInfo::If() + z.Dsat()
1101
104
                };
1102
126
            }
1103
249
            case Fragment::AND_V: {
1104
249
                const auto& x{subs[0].ss};
1105
249
                const auto& y{subs[1].ss};
1106
249
                return {x.Sat() + y.Sat(), {}};
1107
126
            }
1108
6.88k
            case Fragment::AND_B: {
1109
6.88k
                const auto& x{subs[0].ss};
1110
6.88k
                const auto& y{subs[1].ss};
1111
6.88k
                return {x.Sat() + y.Sat() + SatInfo::BinaryOp(), x.Dsat() + y.Dsat() + SatInfo::BinaryOp()};
1112
126
            }
1113
29
            case Fragment::OR_B: {
1114
29
                const auto& x{subs[0].ss};
1115
29
                const auto& y{subs[1].ss};
1116
29
                return {
1117
29
                    ((x.Sat() + y.Dsat()) | (x.Dsat() + y.Sat())) + SatInfo::BinaryOp(),
1118
29
                    x.Dsat() + y.Dsat() + SatInfo::BinaryOp()
1119
29
                };
1120
126
            }
1121
20
            case Fragment::OR_C: {
1122
20
                const auto& x{subs[0].ss};
1123
20
                const auto& y{subs[1].ss};
1124
20
                return {(x.Sat() + SatInfo::If()) | (x.Dsat() + SatInfo::If() + y.Sat()), {}};
1125
126
            }
1126
43
            case Fragment::OR_D: {
1127
43
                const auto& x{subs[0].ss};
1128
43
                const auto& y{subs[1].ss};
1129
43
                return {
1130
43
                    (x.Sat() + SatInfo::OP_IFDUP(true) + SatInfo::If()) | (x.Dsat() + SatInfo::OP_IFDUP(false) + SatInfo::If() + y.Sat()),
1131
43
                    x.Dsat() + SatInfo::OP_IFDUP(false) + SatInfo::If() + y.Dsat()
1132
43
                };
1133
126
            }
1134
398
            case Fragment::OR_I: {
1135
398
                const auto& x{subs[0].ss};
1136
398
                const auto& y{subs[1].ss};
1137
398
                return {SatInfo::If() + (x.Sat() | y.Sat()), SatInfo::If() + (x.Dsat() | y.Dsat())};
1138
126
            }
1139
            // multi(k, key1, key2, ..., key_n) starts off with k+1 stack elements (a 0, plus k
1140
            // signatures), then reaches n+k+3 stack elements after pushing the n keys, plus k and
1141
            // n itself, and ends with 1 stack element (success or failure). Thus, it net removes
1142
            // k elements (from k+1 to 1), while reaching k+n+2 more than it ends with.
1143
49
            case Fragment::MULTI: return {SatInfo(k, k + keys.size() + 2)};
1144
            // multi_a(k, key1, key2, ..., key_n) starts off with n stack elements (the
1145
            // signatures), reaches 1 more (after the first key push), and ends with 1. Thus it net
1146
            // removes n-1 elements (from n to 1) while reaching n more than it ends with.
1147
5
            case Fragment::MULTI_A: return {SatInfo(keys.size() - 1, keys.size())};
1148
7.00k
            case Fragment::WRAP_A:
1149
7.29k
            case Fragment::WRAP_N:
1150
7.77k
            case Fragment::WRAP_S: return subs[0].ss;
1151
1.76k
            case Fragment::WRAP_C: return {
1152
1.76k
                subs[0].ss.Sat() + SatInfo::OP_CHECKSIG(),
1153
1.76k
                subs[0].ss.Dsat() + SatInfo::OP_CHECKSIG()
1154
1.76k
            };
1155
36
            case Fragment::WRAP_D: return {
1156
36
                SatInfo::OP_DUP() + SatInfo::If() + subs[0].ss.Sat(),
1157
36
                SatInfo::OP_DUP() + SatInfo::If()
1158
36
            };
1159
305
            case Fragment::WRAP_V: return {subs[0].ss.Sat() + SatInfo::OP_VERIFY(), {}};
1160
16
            case Fragment::WRAP_J: return {
1161
16
                SatInfo::OP_SIZE() + SatInfo::OP_0NOTEQUAL() + SatInfo::If() + subs[0].ss.Sat(),
1162
16
                SatInfo::OP_SIZE() + SatInfo::OP_0NOTEQUAL() + SatInfo::If()
1163
16
            };
1164
147
            case Fragment::THRESH: {
1165
                // sats[j] is the SatInfo corresponding to all traces reaching j satisfactions.
1166
147
                auto sats = Vector(SatInfo::Empty());
1167
847
                for (size_t i = 0; i < subs.size(); ++i) {
1168
                    // Loop over the subexpressions, processing them one by one. After adding
1169
                    // element i we need to add OP_ADD (if i>0).
1170
700
                    auto add = i ? SatInfo::BinaryOp() : SatInfo::Empty();
1171
                    // Construct a variable that will become the next sats, starting with index 0.
1172
700
                    auto next_sats = Vector(sats[0] + subs[i].ss.Dsat() + add);
1173
                    // Then loop to construct next_sats[1..i].
1174
2.39k
                    for (size_t j = 1; j < sats.size(); ++j) {
1175
1.69k
                        next_sats.push_back(((sats[j] + subs[i].ss.Dsat()) | (sats[j - 1] + subs[i].ss.Sat())) + add);
1176
1.69k
                    }
1177
                    // Finally construct next_sats[i+1].
1178
700
                    next_sats.push_back(sats[sats.size() - 1] + subs[i].ss.Sat() + add);
1179
                    // Switch over.
1180
700
                    sats = std::move(next_sats);
1181
700
                }
1182
                // To satisfy thresh we need k satisfactions; to dissatisfy we need 0. In both
1183
                // cases a push of k and an OP_EQUAL follow.
1184
147
                return {
1185
147
                    sats[k] + SatInfo::Push() + SatInfo::OP_EQUAL(),
1186
147
                    sats[0] + SatInfo::Push() + SatInfo::OP_EQUAL()
1187
147
                };
1188
7.29k
            }
1189
28.4k
        }
1190
28.4k
        assert(false);
1191
0
    }
miniscript::Node<unsigned int>::CalcStackSize() const
Line
Count
Source
1078
1.72M
    internal::StackSize CalcStackSize() const {
1079
1.72M
        using namespace internal;
1080
1.72M
        switch (fragment) {
1081
260
            case Fragment::JUST_0: return {{}, SatInfo::Push()};
1082
13
            case Fragment::JUST_1: return {SatInfo::Push(), {}};
1083
322
            case Fragment::OLDER:
1084
661
            case Fragment::AFTER: return {SatInfo::Push() + SatInfo::Nop(), {}};
1085
1.46k
            case Fragment::PK_K: return {SatInfo::Push()};
1086
475
            case Fragment::PK_H: return {SatInfo::OP_DUP() + SatInfo::Hash() + SatInfo::Push() + SatInfo::OP_EQUALVERIFY()};
1087
42
            case Fragment::SHA256:
1088
93
            case Fragment::RIPEMD160:
1089
157
            case Fragment::HASH256:
1090
230
            case Fragment::HASH160: return {
1091
230
                SatInfo::OP_SIZE() + SatInfo::Push() + SatInfo::OP_EQUALVERIFY() + SatInfo::Hash() + SatInfo::Push() + SatInfo::OP_EQUAL(),
1092
230
                {}
1093
230
            };
1094
136
            case Fragment::ANDOR: {
1095
136
                const auto& x{subs[0].ss};
1096
136
                const auto& y{subs[1].ss};
1097
136
                const auto& z{subs[2].ss};
1098
136
                return {
1099
136
                    (x.Sat() + SatInfo::If() + y.Sat()) | (x.Dsat() + SatInfo::If() + z.Sat()),
1100
136
                    x.Dsat() + SatInfo::If() + z.Dsat()
1101
136
                };
1102
157
            }
1103
724
            case Fragment::AND_V: {
1104
724
                const auto& x{subs[0].ss};
1105
724
                const auto& y{subs[1].ss};
1106
724
                return {x.Sat() + y.Sat(), {}};
1107
157
            }
1108
249
            case Fragment::AND_B: {
1109
249
                const auto& x{subs[0].ss};
1110
249
                const auto& y{subs[1].ss};
1111
249
                return {x.Sat() + y.Sat() + SatInfo::BinaryOp(), x.Dsat() + y.Dsat() + SatInfo::BinaryOp()};
1112
157
            }
1113
70
            case Fragment::OR_B: {
1114
70
                const auto& x{subs[0].ss};
1115
70
                const auto& y{subs[1].ss};
1116
70
                return {
1117
70
                    ((x.Sat() + y.Dsat()) | (x.Dsat() + y.Sat())) + SatInfo::BinaryOp(),
1118
70
                    x.Dsat() + y.Dsat() + SatInfo::BinaryOp()
1119
70
                };
1120
157
            }
1121
40
            case Fragment::OR_C: {
1122
40
                const auto& x{subs[0].ss};
1123
40
                const auto& y{subs[1].ss};
1124
40
                return {(x.Sat() + SatInfo::If()) | (x.Dsat() + SatInfo::If() + y.Sat()), {}};
1125
157
            }
1126
84
            case Fragment::OR_D: {
1127
84
                const auto& x{subs[0].ss};
1128
84
                const auto& y{subs[1].ss};
1129
84
                return {
1130
84
                    (x.Sat() + SatInfo::OP_IFDUP(true) + SatInfo::If()) | (x.Dsat() + SatInfo::OP_IFDUP(false) + SatInfo::If() + y.Sat()),
1131
84
                    x.Dsat() + SatInfo::OP_IFDUP(false) + SatInfo::If() + y.Dsat()
1132
84
                };
1133
157
            }
1134
254
            case Fragment::OR_I: {
1135
254
                const auto& x{subs[0].ss};
1136
254
                const auto& y{subs[1].ss};
1137
254
                return {SatInfo::If() + (x.Sat() | y.Sat()), SatInfo::If() + (x.Dsat() | y.Dsat())};
1138
157
            }
1139
            // multi(k, key1, key2, ..., key_n) starts off with k+1 stack elements (a 0, plus k
1140
            // signatures), then reaches n+k+3 stack elements after pushing the n keys, plus k and
1141
            // n itself, and ends with 1 stack element (success or failure). Thus, it net removes
1142
            // k elements (from k+1 to 1), while reaching k+n+2 more than it ends with.
1143
124
            case Fragment::MULTI: return {SatInfo(k, k + keys.size() + 2)};
1144
            // multi_a(k, key1, key2, ..., key_n) starts off with n stack elements (the
1145
            // signatures), reaches 1 more (after the first key push), and ends with 1. Thus it net
1146
            // removes n-1 elements (from n to 1) while reaching n more than it ends with.
1147
32
            case Fragment::MULTI_A: return {SatInfo(keys.size() - 1, keys.size())};
1148
495
            case Fragment::WRAP_A:
1149
1.71M
            case Fragment::WRAP_N:
1150
1.71M
            case Fragment::WRAP_S: return subs[0].ss;
1151
1.91k
            case Fragment::WRAP_C: return {
1152
1.91k
                subs[0].ss.Sat() + SatInfo::OP_CHECKSIG(),
1153
1.91k
                subs[0].ss.Dsat() + SatInfo::OP_CHECKSIG()
1154
1.91k
            };
1155
72
            case Fragment::WRAP_D: return {
1156
72
                SatInfo::OP_DUP() + SatInfo::If() + subs[0].ss.Sat(),
1157
72
                SatInfo::OP_DUP() + SatInfo::If()
1158
72
            };
1159
801
            case Fragment::WRAP_V: return {subs[0].ss.Sat() + SatInfo::OP_VERIFY(), {}};
1160
0
            case Fragment::WRAP_J: return {
1161
0
                SatInfo::OP_SIZE() + SatInfo::OP_0NOTEQUAL() + SatInfo::If() + subs[0].ss.Sat(),
1162
0
                SatInfo::OP_SIZE() + SatInfo::OP_0NOTEQUAL() + SatInfo::If()
1163
0
            };
1164
242
            case Fragment::THRESH: {
1165
                // sats[j] is the SatInfo corresponding to all traces reaching j satisfactions.
1166
242
                auto sats = Vector(SatInfo::Empty());
1167
1.05k
                for (size_t i = 0; i < subs.size(); ++i) {
1168
                    // Loop over the subexpressions, processing them one by one. After adding
1169
                    // element i we need to add OP_ADD (if i>0).
1170
814
                    auto add = i ? SatInfo::BinaryOp() : SatInfo::Empty();
1171
                    // Construct a variable that will become the next sats, starting with index 0.
1172
814
                    auto next_sats = Vector(sats[0] + subs[i].ss.Dsat() + add);
1173
                    // Then loop to construct next_sats[1..i].
1174
2.12k
                    for (size_t j = 1; j < sats.size(); ++j) {
1175
1.31k
                        next_sats.push_back(((sats[j] + subs[i].ss.Dsat()) | (sats[j - 1] + subs[i].ss.Sat())) + add);
1176
1.31k
                    }
1177
                    // Finally construct next_sats[i+1].
1178
814
                    next_sats.push_back(sats[sats.size() - 1] + subs[i].ss.Sat() + add);
1179
                    // Switch over.
1180
814
                    sats = std::move(next_sats);
1181
814
                }
1182
                // To satisfy thresh we need k satisfactions; to dissatisfy we need 0. In both
1183
                // cases a push of k and an OP_EQUAL follow.
1184
242
                return {
1185
242
                    sats[k] + SatInfo::Push() + SatInfo::OP_EQUAL(),
1186
242
                    sats[0] + SatInfo::Push() + SatInfo::OP_EQUAL()
1187
242
                };
1188
1.71M
            }
1189
1.72M
        }
1190
1.72M
        assert(false);
1191
0
    }
miniscript::Node<XOnlyPubKey>::CalcStackSize() const
Line
Count
Source
1078
1.98M
    internal::StackSize CalcStackSize() const {
1079
1.98M
        using namespace internal;
1080
1.98M
        switch (fragment) {
1081
0
            case Fragment::JUST_0: return {{}, SatInfo::Push()};
1082
0
            case Fragment::JUST_1: return {SatInfo::Push(), {}};
1083
51
            case Fragment::OLDER:
1084
840
            case Fragment::AFTER: return {SatInfo::Push() + SatInfo::Nop(), {}};
1085
3.37k
            case Fragment::PK_K: return {SatInfo::Push()};
1086
336
            case Fragment::PK_H: return {SatInfo::OP_DUP() + SatInfo::Hash() + SatInfo::Push() + SatInfo::OP_EQUALVERIFY()};
1087
0
            case Fragment::SHA256:
1088
0
            case Fragment::RIPEMD160:
1089
12
            case Fragment::HASH256:
1090
12
            case Fragment::HASH160: return {
1091
12
                SatInfo::OP_SIZE() + SatInfo::Push() + SatInfo::OP_EQUALVERIFY() + SatInfo::Hash() + SatInfo::Push() + SatInfo::OP_EQUAL(),
1092
12
                {}
1093
12
            };
1094
0
            case Fragment::ANDOR: {
1095
0
                const auto& x{subs[0].ss};
1096
0
                const auto& y{subs[1].ss};
1097
0
                const auto& z{subs[2].ss};
1098
0
                return {
1099
0
                    (x.Sat() + SatInfo::If() + y.Sat()) | (x.Dsat() + SatInfo::If() + z.Sat()),
1100
0
                    x.Dsat() + SatInfo::If() + z.Dsat()
1101
0
                };
1102
12
            }
1103
880
            case Fragment::AND_V: {
1104
880
                const auto& x{subs[0].ss};
1105
880
                const auto& y{subs[1].ss};
1106
880
                return {x.Sat() + y.Sat(), {}};
1107
12
            }
1108
64
            case Fragment::AND_B: {
1109
64
                const auto& x{subs[0].ss};
1110
64
                const auto& y{subs[1].ss};
1111
64
                return {x.Sat() + y.Sat() + SatInfo::BinaryOp(), x.Dsat() + y.Dsat() + SatInfo::BinaryOp()};
1112
12
            }
1113
28
            case Fragment::OR_B: {
1114
28
                const auto& x{subs[0].ss};
1115
28
                const auto& y{subs[1].ss};
1116
28
                return {
1117
28
                    ((x.Sat() + y.Dsat()) | (x.Dsat() + y.Sat())) + SatInfo::BinaryOp(),
1118
28
                    x.Dsat() + y.Dsat() + SatInfo::BinaryOp()
1119
28
                };
1120
12
            }
1121
0
            case Fragment::OR_C: {
1122
0
                const auto& x{subs[0].ss};
1123
0
                const auto& y{subs[1].ss};
1124
0
                return {(x.Sat() + SatInfo::If()) | (x.Dsat() + SatInfo::If() + y.Sat()), {}};
1125
12
            }
1126
0
            case Fragment::OR_D: {
1127
0
                const auto& x{subs[0].ss};
1128
0
                const auto& y{subs[1].ss};
1129
0
                return {
1130
0
                    (x.Sat() + SatInfo::OP_IFDUP(true) + SatInfo::If()) | (x.Dsat() + SatInfo::OP_IFDUP(false) + SatInfo::If() + y.Sat()),
1131
0
                    x.Dsat() + SatInfo::OP_IFDUP(false) + SatInfo::If() + y.Dsat()
1132
0
                };
1133
12
            }
1134
0
            case Fragment::OR_I: {
1135
0
                const auto& x{subs[0].ss};
1136
0
                const auto& y{subs[1].ss};
1137
0
                return {SatInfo::If() + (x.Sat() | y.Sat()), SatInfo::If() + (x.Dsat() | y.Dsat())};
1138
12
            }
1139
            // multi(k, key1, key2, ..., key_n) starts off with k+1 stack elements (a 0, plus k
1140
            // signatures), then reaches n+k+3 stack elements after pushing the n keys, plus k and
1141
            // n itself, and ends with 1 stack element (success or failure). Thus, it net removes
1142
            // k elements (from k+1 to 1), while reaching k+n+2 more than it ends with.
1143
0
            case Fragment::MULTI: return {SatInfo(k, k + keys.size() + 2)};
1144
            // multi_a(k, key1, key2, ..., key_n) starts off with n stack elements (the
1145
            // signatures), reaches 1 more (after the first key push), and ends with 1. Thus it net
1146
            // removes n-1 elements (from n to 1) while reaching n more than it ends with.
1147
784
            case Fragment::MULTI_A: return {SatInfo(keys.size() - 1, keys.size())};
1148
86
            case Fragment::WRAP_A:
1149
1.97M
            case Fragment::WRAP_N:
1150
1.97M
            case Fragment::WRAP_S: return subs[0].ss;
1151
3.70k
            case Fragment::WRAP_C: return {
1152
3.70k
                subs[0].ss.Sat() + SatInfo::OP_CHECKSIG(),
1153
3.70k
                subs[0].ss.Dsat() + SatInfo::OP_CHECKSIG()
1154
3.70k
            };
1155
6
            case Fragment::WRAP_D: return {
1156
6
                SatInfo::OP_DUP() + SatInfo::If() + subs[0].ss.Sat(),
1157
6
                SatInfo::OP_DUP() + SatInfo::If()
1158
6
            };
1159
886
            case Fragment::WRAP_V: return {subs[0].ss.Sat() + SatInfo::OP_VERIFY(), {}};
1160
0
            case Fragment::WRAP_J: return {
1161
0
                SatInfo::OP_SIZE() + SatInfo::OP_0NOTEQUAL() + SatInfo::If() + subs[0].ss.Sat(),
1162
0
                SatInfo::OP_SIZE() + SatInfo::OP_0NOTEQUAL() + SatInfo::If()
1163
0
            };
1164
22
            case Fragment::THRESH: {
1165
                // sats[j] is the SatInfo corresponding to all traces reaching j satisfactions.
1166
22
                auto sats = Vector(SatInfo::Empty());
1167
88
                for (size_t i = 0; i < subs.size(); ++i) {
1168
                    // Loop over the subexpressions, processing them one by one. After adding
1169
                    // element i we need to add OP_ADD (if i>0).
1170
66
                    auto add = i ? SatInfo::BinaryOp() : SatInfo::Empty();
1171
                    // Construct a variable that will become the next sats, starting with index 0.
1172
66
                    auto next_sats = Vector(sats[0] + subs[i].ss.Dsat() + add);
1173
                    // Then loop to construct next_sats[1..i].
1174
132
                    for (size_t j = 1; j < sats.size(); ++j) {
1175
66
                        next_sats.push_back(((sats[j] + subs[i].ss.Dsat()) | (sats[j - 1] + subs[i].ss.Sat())) + add);
1176
66
                    }
1177
                    // Finally construct next_sats[i+1].
1178
66
                    next_sats.push_back(sats[sats.size() - 1] + subs[i].ss.Sat() + add);
1179
                    // Switch over.
1180
66
                    sats = std::move(next_sats);
1181
66
                }
1182
                // To satisfy thresh we need k satisfactions; to dissatisfy we need 0. In both
1183
                // cases a push of k and an OP_EQUAL follow.
1184
22
                return {
1185
22
                    sats[k] + SatInfo::Push() + SatInfo::OP_EQUAL(),
1186
22
                    sats[0] + SatInfo::Push() + SatInfo::OP_EQUAL()
1187
22
                };
1188
1.97M
            }
1189
1.98M
        }
1190
1.98M
        assert(false);
1191
0
    }
1192
1193
3.74M
    internal::WitnessSize CalcWitnessSize() const {
1194
3.74M
        const uint32_t sig_size = IsTapscript(m_script_ctx) ? 1 + 65 : 1 + 72;
1195
3.74M
        const uint32_t pubkey_size = IsTapscript(m_script_ctx) ? 1 + 32 : 1 + 33;
1196
3.74M
        switch (fragment) {
1197
709
            case Fragment::JUST_0: return {{}, 0};
1198
245
            case Fragment::JUST_1:
1199
8.19k
            case Fragment::OLDER:
1200
9.70k
            case Fragment::AFTER: return {0, {}};
1201
6.51k
            case Fragment::PK_K: return {sig_size, 1};
1202
934
            case Fragment::PK_H: return {sig_size + pubkey_size, 1 + pubkey_size};
1203
102
            case Fragment::SHA256:
1204
179
            case Fragment::RIPEMD160:
1205
295
            case Fragment::HASH256:
1206
392
            case Fragment::HASH160: return {1 + 32, {}};
1207
240
            case Fragment::ANDOR: {
1208
240
                const auto sat{(subs[0].ws.sat + subs[1].ws.sat) | (subs[0].ws.dsat + subs[2].ws.sat)};
1209
240
                const auto dsat{subs[0].ws.dsat + subs[2].ws.dsat};
1210
240
                return {sat, dsat};
1211
295
            }
1212
1.85k
            case Fragment::AND_V: return {subs[0].ws.sat + subs[1].ws.sat, {}};
1213
7.19k
            case Fragment::AND_B: return {subs[0].ws.sat + subs[1].ws.sat, subs[0].ws.dsat + subs[1].ws.dsat};
1214
127
            case Fragment::OR_B: {
1215
127
                const auto sat{(subs[0].ws.dsat + subs[1].ws.sat) | (subs[0].ws.sat + subs[1].ws.dsat)};
1216
127
                const auto dsat{subs[0].ws.dsat + subs[1].ws.dsat};
1217
127
                return {sat, dsat};
1218
295
            }
1219
60
            case Fragment::OR_C: return {subs[0].ws.sat | (subs[0].ws.dsat + subs[1].ws.sat), {}};
1220
127
            case Fragment::OR_D: return {subs[0].ws.sat | (subs[0].ws.dsat + subs[1].ws.sat), subs[0].ws.dsat + subs[1].ws.dsat};
1221
652
            case Fragment::OR_I: return {(subs[0].ws.sat + 1 + 1) | (subs[1].ws.sat + 1), (subs[0].ws.dsat + 1 + 1) | (subs[1].ws.dsat + 1)};
1222
173
            case Fragment::MULTI: return {k * sig_size + 1, k + 1};
1223
821
            case Fragment::MULTI_A: return {k * sig_size + static_cast<uint32_t>(keys.size()) - k, static_cast<uint32_t>(keys.size())};
1224
7.58k
            case Fragment::WRAP_A:
1225
3.70M
            case Fragment::WRAP_N:
1226
3.70M
            case Fragment::WRAP_S:
1227
3.71M
            case Fragment::WRAP_C: return subs[0].ws;
1228
114
            case Fragment::WRAP_D: return {1 + 1 + subs[0].ws.sat, 1};
1229
1.99k
            case Fragment::WRAP_V: return {subs[0].ws.sat, {}};
1230
16
            case Fragment::WRAP_J: return {subs[0].ws.sat, 1};
1231
411
            case Fragment::THRESH: {
1232
411
                auto sats = Vector(internal::MaxInt<uint32_t>(0));
1233
1.58k
                for (const auto& sub : subs) {
1234
1.58k
                    auto next_sats = Vector(sats[0] + sub.ws.dsat);
1235
4.65k
                    for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub.ws.dsat) | (sats[j - 1] + sub.ws.sat));
1236
1.58k
                    next_sats.push_back(sats[sats.size() - 1] + sub.ws.sat);
1237
1.58k
                    sats = std::move(next_sats);
1238
1.58k
                }
1239
411
                assert(k < sats.size());
1240
411
                return {sats[k], sats[0]};
1241
411
            }
1242
3.74M
        }
1243
3.74M
        assert(false);
1244
0
    }
miniscript::Node<CPubKey>::CalcWitnessSize() const
Line
Count
Source
1193
28.4k
    internal::WitnessSize CalcWitnessSize() const {
1194
28.4k
        const uint32_t sig_size = IsTapscript(m_script_ctx) ? 1 + 65 : 1 + 72;
1195
28.4k
        const uint32_t pubkey_size = IsTapscript(m_script_ctx) ? 1 + 32 : 1 + 33;
1196
28.4k
        switch (fragment) {
1197
449
            case Fragment::JUST_0: return {{}, 0};
1198
232
            case Fragment::JUST_1:
1199
7.80k
            case Fragment::OLDER:
1200
8.18k
            case Fragment::AFTER: return {0, {}};
1201
1.67k
            case Fragment::PK_K: return {sig_size, 1};
1202
123
            case Fragment::PK_H: return {sig_size + pubkey_size, 1 + pubkey_size};
1203
60
            case Fragment::SHA256:
1204
86
            case Fragment::RIPEMD160:
1205
126
            case Fragment::HASH256:
1206
150
            case Fragment::HASH160: return {1 + 32, {}};
1207
104
            case Fragment::ANDOR: {
1208
104
                const auto sat{(subs[0].ws.sat + subs[1].ws.sat) | (subs[0].ws.dsat + subs[2].ws.sat)};
1209
104
                const auto dsat{subs[0].ws.dsat + subs[2].ws.dsat};
1210
104
                return {sat, dsat};
1211
126
            }
1212
249
            case Fragment::AND_V: return {subs[0].ws.sat + subs[1].ws.sat, {}};
1213
6.88k
            case Fragment::AND_B: return {subs[0].ws.sat + subs[1].ws.sat, subs[0].ws.dsat + subs[1].ws.dsat};
1214
29
            case Fragment::OR_B: {
1215
29
                const auto sat{(subs[0].ws.dsat + subs[1].ws.sat) | (subs[0].ws.sat + subs[1].ws.dsat)};
1216
29
                const auto dsat{subs[0].ws.dsat + subs[1].ws.dsat};
1217
29
                return {sat, dsat};
1218
126
            }
1219
20
            case Fragment::OR_C: return {subs[0].ws.sat | (subs[0].ws.dsat + subs[1].ws.sat), {}};
1220
43
            case Fragment::OR_D: return {subs[0].ws.sat | (subs[0].ws.dsat + subs[1].ws.sat), subs[0].ws.dsat + subs[1].ws.dsat};
1221
398
            case Fragment::OR_I: return {(subs[0].ws.sat + 1 + 1) | (subs[1].ws.sat + 1), (subs[0].ws.dsat + 1 + 1) | (subs[1].ws.dsat + 1)};
1222
49
            case Fragment::MULTI: return {k * sig_size + 1, k + 1};
1223
5
            case Fragment::MULTI_A: return {k * sig_size + static_cast<uint32_t>(keys.size()) - k, static_cast<uint32_t>(keys.size())};
1224
7.00k
            case Fragment::WRAP_A:
1225
7.29k
            case Fragment::WRAP_N:
1226
7.77k
            case Fragment::WRAP_S:
1227
9.53k
            case Fragment::WRAP_C: return subs[0].ws;
1228
36
            case Fragment::WRAP_D: return {1 + 1 + subs[0].ws.sat, 1};
1229
305
            case Fragment::WRAP_V: return {subs[0].ws.sat, {}};
1230
16
            case Fragment::WRAP_J: return {subs[0].ws.sat, 1};
1231
147
            case Fragment::THRESH: {
1232
147
                auto sats = Vector(internal::MaxInt<uint32_t>(0));
1233
700
                for (const auto& sub : subs) {
1234
700
                    auto next_sats = Vector(sats[0] + sub.ws.dsat);
1235
2.39k
                    for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub.ws.dsat) | (sats[j - 1] + sub.ws.sat));
1236
700
                    next_sats.push_back(sats[sats.size() - 1] + sub.ws.sat);
1237
700
                    sats = std::move(next_sats);
1238
700
                }
1239
147
                assert(k < sats.size());
1240
147
                return {sats[k], sats[0]};
1241
147
            }
1242
28.4k
        }
1243
28.4k
        assert(false);
1244
0
    }
miniscript::Node<unsigned int>::CalcWitnessSize() const
Line
Count
Source
1193
1.72M
    internal::WitnessSize CalcWitnessSize() const {
1194
1.72M
        const uint32_t sig_size = IsTapscript(m_script_ctx) ? 1 + 65 : 1 + 72;
1195
1.72M
        const uint32_t pubkey_size = IsTapscript(m_script_ctx) ? 1 + 32 : 1 + 33;
1196
1.72M
        switch (fragment) {
1197
260
            case Fragment::JUST_0: return {{}, 0};
1198
13
            case Fragment::JUST_1:
1199
335
            case Fragment::OLDER:
1200
674
            case Fragment::AFTER: return {0, {}};
1201
1.46k
            case Fragment::PK_K: return {sig_size, 1};
1202
475
            case Fragment::PK_H: return {sig_size + pubkey_size, 1 + pubkey_size};
1203
42
            case Fragment::SHA256:
1204
93
            case Fragment::RIPEMD160:
1205
157
            case Fragment::HASH256:
1206
230
            case Fragment::HASH160: return {1 + 32, {}};
1207
136
            case Fragment::ANDOR: {
1208
136
                const auto sat{(subs[0].ws.sat + subs[1].ws.sat) | (subs[0].ws.dsat + subs[2].ws.sat)};
1209
136
                const auto dsat{subs[0].ws.dsat + subs[2].ws.dsat};
1210
136
                return {sat, dsat};
1211
157
            }
1212
724
            case Fragment::AND_V: return {subs[0].ws.sat + subs[1].ws.sat, {}};
1213
249
            case Fragment::AND_B: return {subs[0].ws.sat + subs[1].ws.sat, subs[0].ws.dsat + subs[1].ws.dsat};
1214
70
            case Fragment::OR_B: {
1215
70
                const auto sat{(subs[0].ws.dsat + subs[1].ws.sat) | (subs[0].ws.sat + subs[1].ws.dsat)};
1216
70
                const auto dsat{subs[0].ws.dsat + subs[1].ws.dsat};
1217
70
                return {sat, dsat};
1218
157
            }
1219
40
            case Fragment::OR_C: return {subs[0].ws.sat | (subs[0].ws.dsat + subs[1].ws.sat), {}};
1220
84
            case Fragment::OR_D: return {subs[0].ws.sat | (subs[0].ws.dsat + subs[1].ws.sat), subs[0].ws.dsat + subs[1].ws.dsat};
1221
254
            case Fragment::OR_I: return {(subs[0].ws.sat + 1 + 1) | (subs[1].ws.sat + 1), (subs[0].ws.dsat + 1 + 1) | (subs[1].ws.dsat + 1)};
1222
124
            case Fragment::MULTI: return {k * sig_size + 1, k + 1};
1223
32
            case Fragment::MULTI_A: return {k * sig_size + static_cast<uint32_t>(keys.size()) - k, static_cast<uint32_t>(keys.size())};
1224
495
            case Fragment::WRAP_A:
1225
1.71M
            case Fragment::WRAP_N:
1226
1.71M
            case Fragment::WRAP_S:
1227
1.72M
            case Fragment::WRAP_C: return subs[0].ws;
1228
72
            case Fragment::WRAP_D: return {1 + 1 + subs[0].ws.sat, 1};
1229
801
            case Fragment::WRAP_V: return {subs[0].ws.sat, {}};
1230
0
            case Fragment::WRAP_J: return {subs[0].ws.sat, 1};
1231
242
            case Fragment::THRESH: {
1232
242
                auto sats = Vector(internal::MaxInt<uint32_t>(0));
1233
814
                for (const auto& sub : subs) {
1234
814
                    auto next_sats = Vector(sats[0] + sub.ws.dsat);
1235
2.12k
                    for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub.ws.dsat) | (sats[j - 1] + sub.ws.sat));
1236
814
                    next_sats.push_back(sats[sats.size() - 1] + sub.ws.sat);
1237
814
                    sats = std::move(next_sats);
1238
814
                }
1239
242
                assert(k < sats.size());
1240
242
                return {sats[k], sats[0]};
1241
242
            }
1242
1.72M
        }
1243
1.72M
        assert(false);
1244
0
    }
miniscript::Node<XOnlyPubKey>::CalcWitnessSize() const
Line
Count
Source
1193
1.98M
    internal::WitnessSize CalcWitnessSize() const {
1194
1.98M
        const uint32_t sig_size = IsTapscript(m_script_ctx) ? 1 + 65 : 1 + 72;
1195
1.98M
        const uint32_t pubkey_size = IsTapscript(m_script_ctx) ? 1 + 32 : 1 + 33;
1196
1.98M
        switch (fragment) {
1197
0
            case Fragment::JUST_0: return {{}, 0};
1198
0
            case Fragment::JUST_1:
1199
51
            case Fragment::OLDER:
1200
840
            case Fragment::AFTER: return {0, {}};
1201
3.37k
            case Fragment::PK_K: return {sig_size, 1};
1202
336
            case Fragment::PK_H: return {sig_size + pubkey_size, 1 + pubkey_size};
1203
0
            case Fragment::SHA256:
1204
0
            case Fragment::RIPEMD160:
1205
12
            case Fragment::HASH256:
1206
12
            case Fragment::HASH160: return {1 + 32, {}};
1207
0
            case Fragment::ANDOR: {
1208
0
                const auto sat{(subs[0].ws.sat + subs[1].ws.sat) | (subs[0].ws.dsat + subs[2].ws.sat)};
1209
0
                const auto dsat{subs[0].ws.dsat + subs[2].ws.dsat};
1210
0
                return {sat, dsat};
1211
12
            }
1212
880
            case Fragment::AND_V: return {subs[0].ws.sat + subs[1].ws.sat, {}};
1213
64
            case Fragment::AND_B: return {subs[0].ws.sat + subs[1].ws.sat, subs[0].ws.dsat + subs[1].ws.dsat};
1214
28
            case Fragment::OR_B: {
1215
28
                const auto sat{(subs[0].ws.dsat + subs[1].ws.sat) | (subs[0].ws.sat + subs[1].ws.dsat)};
1216
28
                const auto dsat{subs[0].ws.dsat + subs[1].ws.dsat};
1217
28
                return {sat, dsat};
1218
12
            }
1219
0
            case Fragment::OR_C: return {subs[0].ws.sat | (subs[0].ws.dsat + subs[1].ws.sat), {}};
1220
0
            case Fragment::OR_D: return {subs[0].ws.sat | (subs[0].ws.dsat + subs[1].ws.sat), subs[0].ws.dsat + subs[1].ws.dsat};
1221
0
            case Fragment::OR_I: return {(subs[0].ws.sat + 1 + 1) | (subs[1].ws.sat + 1), (subs[0].ws.dsat + 1 + 1) | (subs[1].ws.dsat + 1)};
1222
0
            case Fragment::MULTI: return {k * sig_size + 1, k + 1};
1223
784
            case Fragment::MULTI_A: return {k * sig_size + static_cast<uint32_t>(keys.size()) - k, static_cast<uint32_t>(keys.size())};
1224
86
            case Fragment::WRAP_A:
1225
1.97M
            case Fragment::WRAP_N:
1226
1.97M
            case Fragment::WRAP_S:
1227
1.98M
            case Fragment::WRAP_C: return subs[0].ws;
1228
6
            case Fragment::WRAP_D: return {1 + 1 + subs[0].ws.sat, 1};
1229
886
            case Fragment::WRAP_V: return {subs[0].ws.sat, {}};
1230
0
            case Fragment::WRAP_J: return {subs[0].ws.sat, 1};
1231
22
            case Fragment::THRESH: {
1232
22
                auto sats = Vector(internal::MaxInt<uint32_t>(0));
1233
66
                for (const auto& sub : subs) {
1234
66
                    auto next_sats = Vector(sats[0] + sub.ws.dsat);
1235
132
                    for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub.ws.dsat) | (sats[j - 1] + sub.ws.sat));
1236
66
                    next_sats.push_back(sats[sats.size() - 1] + sub.ws.sat);
1237
66
                    sats = std::move(next_sats);
1238
66
                }
1239
22
                assert(k < sats.size());
1240
22
                return {sats[k], sats[0]};
1241
22
            }
1242
1.98M
        }
1243
1.98M
        assert(false);
1244
0
    }
1245
1246
    template<typename Ctx>
1247
9.36k
    internal::InputResult ProduceInput(const Ctx& ctx) const {
1248
9.36k
        using namespace internal;
1249
1250
        // Internal function which is invoked for every tree node, constructing satisfaction/dissatisfactions
1251
        // given those of its subnodes.
1252
3.60M
        auto helper = [&ctx](const Node& node, std::span<InputResult> subres) -> InputResult {
1253
3.60M
            switch (node.fragment) {
1254
378k
                case Fragment::PK_K: {
1255
378k
                    std::vector<unsigned char> sig;
1256
378k
                    Availability avail = ctx.Sign(node.keys[0], sig);
1257
378k
                    return {ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
1258
0
                }
1259
1.11k
                case Fragment::PK_H: {
1260
1.11k
                    std::vector<unsigned char> key = ctx.ToPKBytes(node.keys[0]), sig;
1261
1.11k
                    Availability avail = ctx.Sign(node.keys[0], sig);
1262
1.11k
                    return {ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
1263
0
                }
1264
940
                case Fragment::MULTI_A: {
1265
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1266
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1267
940
                    std::vector<InputStack> sats = Vector(EMPTY);
1268
93.2k
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1269
                        // Get the signature for the i'th key in reverse order (the signature for the first key needs to
1270
                        // be at the top of the stack, contrary to CHECKMULTISIG's satisfaction).
1271
92.3k
                        std::vector<unsigned char> sig;
1272
92.3k
                        Availability avail = ctx.Sign(node.keys[node.keys.size() - 1 - i], sig);
1273
                        // Compute signature stack for just this key.
1274
92.3k
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1275
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1276
                        // next_sats[j] are equal to either the existing sats[j] + ZERO, or sats[j-1] plus a signature
1277
                        // for the current (i'th) key. The very last element needs all signatures filled.
1278
92.3k
                        std::vector<InputStack> next_sats;
1279
92.3k
                        next_sats.push_back(sats[0] + ZERO);
1280
43.9M
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + ZERO) | (std::move(sats[j - 1]) + sat));
1281
92.3k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1282
                        // Switch over.
1283
92.3k
                        sats = std::move(next_sats);
1284
92.3k
                    }
1285
                    // The dissatisfaction consists of as many empty vectors as there are keys, which is the same as
1286
                    // satisfying 0 keys.
1287
940
                    auto& nsat{sats[0]};
1288
940
                    CHECK_NONFATAL(node.k != 0);
1289
940
                    assert(node.k < sats.size());
1290
940
                    return {std::move(nsat), std::move(sats[node.k])};
1291
940
                }
1292
384
                case Fragment::MULTI: {
1293
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1294
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1295
                    // sats[0] starts off being {0}, due to the CHECKMULTISIG bug that pops off one element too many.
1296
384
                    std::vector<InputStack> sats = Vector(ZERO);
1297
1.14k
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1298
756
                        std::vector<unsigned char> sig;
1299
756
                        Availability avail = ctx.Sign(node.keys[i], sig);
1300
                        // Compute signature stack for just the i'th key.
1301
756
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1302
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1303
                        // next_sats[j] are equal to either the existing sats[j], or sats[j-1] plus a signature for the
1304
                        // current (i'th) key. The very last element needs all signatures filled.
1305
756
                        std::vector<InputStack> next_sats;
1306
756
                        next_sats.push_back(sats[0]);
1307
1.20k
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
1308
756
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1309
                        // Switch over.
1310
756
                        sats = std::move(next_sats);
1311
756
                    }
1312
                    // The dissatisfaction consists of k+1 stack elements all equal to 0.
1313
384
                    InputStack nsat = ZERO;
1314
1.11k
                    for (size_t i = 0; i < node.k; ++i) nsat = std::move(nsat) + ZERO;
1315
384
                    assert(node.k < sats.size());
1316
384
                    return {std::move(nsat), std::move(sats[node.k])};
1317
384
                }
1318
506
                case Fragment::THRESH: {
1319
                    // sats[k] represents the best stack that satisfies k out of the *last* i subexpressions.
1320
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1321
                    // sats[0] starts off empty.
1322
506
                    std::vector<InputStack> sats = Vector(EMPTY);
1323
2.27k
                    for (size_t i = 0; i < subres.size(); ++i) {
1324
                        // Introduce an alias for the i'th last satisfaction/dissatisfaction.
1325
1.76k
                        auto& res = subres[subres.size() - i - 1];
1326
                        // Compute the next sats vector: next_sats[0] is sats[0] plus res.nsat (thus containing all dissatisfactions
1327
                        // so far. next_sats[j] is either sats[j] + res.nsat (reusing j earlier satisfactions) or sats[j-1] + res.sat
1328
                        // (reusing j-1 earlier satisfactions plus a new one). The very last next_sats[j] is all satisfactions.
1329
1.76k
                        std::vector<InputStack> next_sats;
1330
1.76k
                        next_sats.push_back(sats[0] + res.nsat);
1331
4.57k
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + res.nsat) | (std::move(sats[j - 1]) + res.sat));
1332
1.76k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
1333
                        // Switch over.
1334
1.76k
                        sats = std::move(next_sats);
1335
1.76k
                    }
1336
                    // At this point, sats[k].sat is the best satisfaction for the overall thresh() node. The best dissatisfaction
1337
                    // is computed by gathering all sats[i].nsat for i != k.
1338
506
                    InputStack nsat = INVALID;
1339
2.78k
                    for (size_t i = 0; i < sats.size(); ++i) {
1340
                        // i==k is the satisfaction; i==0 is the canonical dissatisfaction;
1341
                        // the rest are non-canonical (a no-signature dissatisfaction - the i=0
1342
                        // form - is always available) and malleable (due to overcompleteness).
1343
                        // Marking the solutions malleable here is not strictly necessary, as they
1344
                        // should already never be picked in non-malleable solutions due to the
1345
                        // availability of the i=0 form.
1346
2.27k
                        if (i != 0 && i != node.k) sats[i].SetMalleable().SetNonCanon();
1347
                        // Include all dissatisfactions (even these non-canonical ones) in nsat.
1348
2.27k
                        if (i != node.k) nsat = std::move(nsat) | std::move(sats[i]);
1349
2.27k
                    }
1350
506
                    assert(node.k < sats.size());
1351
506
                    return {std::move(nsat), std::move(sats[node.k])};
1352
506
                }
1353
37.0k
                case Fragment::OLDER: {
1354
37.0k
                    return {INVALID, ctx.CheckOlder(node.k) ? EMPTY : INVALID};
1355
506
                }
1356
2.34k
                case Fragment::AFTER: {
1357
2.34k
                    return {INVALID, ctx.CheckAfter(node.k) ? EMPTY : INVALID};
1358
506
                }
1359
521
                case Fragment::SHA256: {
1360
521
                    std::vector<unsigned char> preimage;
1361
521
                    Availability avail = ctx.SatSHA256(node.data, preimage);
1362
521
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1363
506
                }
1364
222
                case Fragment::RIPEMD160: {
1365
222
                    std::vector<unsigned char> preimage;
1366
222
                    Availability avail = ctx.SatRIPEMD160(node.data, preimage);
1367
222
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1368
506
                }
1369
396
                case Fragment::HASH256: {
1370
396
                    std::vector<unsigned char> preimage;
1371
396
                    Availability avail = ctx.SatHASH256(node.data, preimage);
1372
396
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1373
506
                }
1374
168
                case Fragment::HASH160: {
1375
168
                    std::vector<unsigned char> preimage;
1376
168
                    Availability avail = ctx.SatHASH160(node.data, preimage);
1377
168
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1378
506
                }
1379
2.30k
                case Fragment::AND_V: {
1380
2.30k
                    auto& x = subres[0], &y = subres[1];
1381
                    // As the dissatisfaction here only consist of a single option, it doesn't
1382
                    // actually need to be listed (it's not required for reasoning about malleability of
1383
                    // other options), and is never required (no valid miniscript relies on the ability
1384
                    // to satisfy the type V left subexpression). It's still listed here for
1385
                    // completeness, as a hypothetical (not currently implemented) satisfier that doesn't
1386
                    // care about malleability might in some cases prefer it still.
1387
2.30k
                    return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
1388
506
                }
1389
407k
                case Fragment::AND_B: {
1390
407k
                    auto& x = subres[0], &y = subres[1];
1391
                    // Note that it is not strictly necessary to mark the 2nd and 3rd dissatisfaction here
1392
                    // as malleable. While they are definitely malleable, they are also non-canonical due
1393
                    // to the guaranteed existence of a no-signature other dissatisfaction (the 1st)
1394
                    // option. Because of that, the 2nd and 3rd option will never be chosen, even if they
1395
                    // weren't marked as malleable.
1396
407k
                    return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
1397
506
                }
1398
172
                case Fragment::OR_B: {
1399
172
                    auto& x = subres[0], &z = subres[1];
1400
                    // The (sat(Z) sat(X)) solution is overcomplete (attacker can change either into dsat).
1401
172
                    return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
1402
506
                }
1403
90
                case Fragment::OR_C: {
1404
90
                    auto& x = subres[0], &z = subres[1];
1405
90
                    return {INVALID, std::move(x.sat) | (z.sat + x.nsat)};
1406
506
                }
1407
317
                case Fragment::OR_D: {
1408
317
                    auto& x = subres[0], &z = subres[1];
1409
317
                    return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
1410
506
                }
1411
1.82k
                case Fragment::OR_I: {
1412
1.82k
                    auto& x = subres[0], &z = subres[1];
1413
1.82k
                    return {(x.nsat + ONE) | (z.nsat + ZERO), (x.sat + ONE) | (z.sat + ZERO)};
1414
506
                }
1415
710
                case Fragment::ANDOR: {
1416
710
                    auto& x = subres[0], &y = subres[1], &z = subres[2];
1417
710
                    return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
1418
506
                }
1419
408k
                case Fragment::WRAP_A:
1420
409k
                case Fragment::WRAP_S:
1421
788k
                case Fragment::WRAP_C:
1422
2.76M
                case Fragment::WRAP_N:
1423
2.76M
                    return std::move(subres[0]);
1424
125
                case Fragment::WRAP_D: {
1425
125
                    auto &x = subres[0];
1426
125
                    return {ZERO, x.sat + ONE};
1427
788k
                }
1428
198
                case Fragment::WRAP_J: {
1429
198
                    auto &x = subres[0];
1430
                    // If a dissatisfaction with a nonzero top stack element exists, an alternative dissatisfaction exists.
1431
                    // As the dissatisfaction logic currently doesn't keep track of this nonzeroness property, and thus even
1432
                    // if a dissatisfaction with a top zero element is found, we don't know whether another one with a
1433
                    // nonzero top stack element exists. Make the conservative assumption that whenever the subexpression is weakly
1434
                    // dissatisfiable, this alternative dissatisfaction exists and leads to malleability.
1435
198
                    return {InputStack(ZERO).SetMalleable(x.nsat.available != Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
1436
788k
                }
1437
2.63k
                case Fragment::WRAP_V: {
1438
2.63k
                    auto &x = subres[0];
1439
2.63k
                    return {INVALID, std::move(x.sat)};
1440
788k
                }
1441
1.74k
                case Fragment::JUST_0: return {EMPTY, INVALID};
1442
972
                case Fragment::JUST_1: return {INVALID, EMPTY};
1443
3.60M
            }
1444
3.60M
            assert(false);
1445
0
            return {INVALID, INVALID};
1446
0
        };
miniscript_tests.cpp:miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)::operator()(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>) const
Line
Count
Source
1252
1.61M
        auto helper = [&ctx](const Node& node, std::span<InputResult> subres) -> InputResult {
1253
1.61M
            switch (node.fragment) {
1254
374k
                case Fragment::PK_K: {
1255
374k
                    std::vector<unsigned char> sig;
1256
374k
                    Availability avail = ctx.Sign(node.keys[0], sig);
1257
374k
                    return {ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
1258
0
                }
1259
708
                case Fragment::PK_H: {
1260
708
                    std::vector<unsigned char> key = ctx.ToPKBytes(node.keys[0]), sig;
1261
708
                    Availability avail = ctx.Sign(node.keys[0], sig);
1262
708
                    return {ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
1263
0
                }
1264
156
                case Fragment::MULTI_A: {
1265
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1266
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1267
156
                    std::vector<InputStack> sats = Vector(EMPTY);
1268
2.97k
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1269
                        // Get the signature for the i'th key in reverse order (the signature for the first key needs to
1270
                        // be at the top of the stack, contrary to CHECKMULTISIG's satisfaction).
1271
2.82k
                        std::vector<unsigned char> sig;
1272
2.82k
                        Availability avail = ctx.Sign(node.keys[node.keys.size() - 1 - i], sig);
1273
                        // Compute signature stack for just this key.
1274
2.82k
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1275
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1276
                        // next_sats[j] are equal to either the existing sats[j] + ZERO, or sats[j-1] plus a signature
1277
                        // for the current (i'th) key. The very last element needs all signatures filled.
1278
2.82k
                        std::vector<InputStack> next_sats;
1279
2.82k
                        next_sats.push_back(sats[0] + ZERO);
1280
30.5k
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + ZERO) | (std::move(sats[j - 1]) + sat));
1281
2.82k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1282
                        // Switch over.
1283
2.82k
                        sats = std::move(next_sats);
1284
2.82k
                    }
1285
                    // The dissatisfaction consists of as many empty vectors as there are keys, which is the same as
1286
                    // satisfying 0 keys.
1287
156
                    auto& nsat{sats[0]};
1288
156
                    CHECK_NONFATAL(node.k != 0);
1289
156
                    assert(node.k < sats.size());
1290
156
                    return {std::move(nsat), std::move(sats[node.k])};
1291
156
                }
1292
360
                case Fragment::MULTI: {
1293
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1294
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1295
                    // sats[0] starts off being {0}, due to the CHECKMULTISIG bug that pops off one element too many.
1296
360
                    std::vector<InputStack> sats = Vector(ZERO);
1297
1.06k
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1298
708
                        std::vector<unsigned char> sig;
1299
708
                        Availability avail = ctx.Sign(node.keys[i], sig);
1300
                        // Compute signature stack for just the i'th key.
1301
708
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1302
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1303
                        // next_sats[j] are equal to either the existing sats[j], or sats[j-1] plus a signature for the
1304
                        // current (i'th) key. The very last element needs all signatures filled.
1305
708
                        std::vector<InputStack> next_sats;
1306
708
                        next_sats.push_back(sats[0]);
1307
1.12k
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
1308
708
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1309
                        // Switch over.
1310
708
                        sats = std::move(next_sats);
1311
708
                    }
1312
                    // The dissatisfaction consists of k+1 stack elements all equal to 0.
1313
360
                    InputStack nsat = ZERO;
1314
1.06k
                    for (size_t i = 0; i < node.k; ++i) nsat = std::move(nsat) + ZERO;
1315
360
                    assert(node.k < sats.size());
1316
360
                    return {std::move(nsat), std::move(sats[node.k])};
1317
360
                }
1318
372
                case Fragment::THRESH: {
1319
                    // sats[k] represents the best stack that satisfies k out of the *last* i subexpressions.
1320
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1321
                    // sats[0] starts off empty.
1322
372
                    std::vector<InputStack> sats = Vector(EMPTY);
1323
1.47k
                    for (size_t i = 0; i < subres.size(); ++i) {
1324
                        // Introduce an alias for the i'th last satisfaction/dissatisfaction.
1325
1.10k
                        auto& res = subres[subres.size() - i - 1];
1326
                        // Compute the next sats vector: next_sats[0] is sats[0] plus res.nsat (thus containing all dissatisfactions
1327
                        // so far. next_sats[j] is either sats[j] + res.nsat (reusing j earlier satisfactions) or sats[j-1] + res.sat
1328
                        // (reusing j-1 earlier satisfactions plus a new one). The very last next_sats[j] is all satisfactions.
1329
1.10k
                        std::vector<InputStack> next_sats;
1330
1.10k
                        next_sats.push_back(sats[0] + res.nsat);
1331
2.25k
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + res.nsat) | (std::move(sats[j - 1]) + res.sat));
1332
1.10k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
1333
                        // Switch over.
1334
1.10k
                        sats = std::move(next_sats);
1335
1.10k
                    }
1336
                    // At this point, sats[k].sat is the best satisfaction for the overall thresh() node. The best dissatisfaction
1337
                    // is computed by gathering all sats[i].nsat for i != k.
1338
372
                    InputStack nsat = INVALID;
1339
1.84k
                    for (size_t i = 0; i < sats.size(); ++i) {
1340
                        // i==k is the satisfaction; i==0 is the canonical dissatisfaction;
1341
                        // the rest are non-canonical (a no-signature dissatisfaction - the i=0
1342
                        // form - is always available) and malleable (due to overcompleteness).
1343
                        // Marking the solutions malleable here is not strictly necessary, as they
1344
                        // should already never be picked in non-malleable solutions due to the
1345
                        // availability of the i=0 form.
1346
1.47k
                        if (i != 0 && i != node.k) sats[i].SetMalleable().SetNonCanon();
1347
                        // Include all dissatisfactions (even these non-canonical ones) in nsat.
1348
1.47k
                        if (i != node.k) nsat = std::move(nsat) | std::move(sats[i]);
1349
1.47k
                    }
1350
372
                    assert(node.k < sats.size());
1351
372
                    return {std::move(nsat), std::move(sats[node.k])};
1352
372
                }
1353
36.9k
                case Fragment::OLDER: {
1354
36.9k
                    return {INVALID, ctx.CheckOlder(node.k) ? EMPTY : INVALID};
1355
372
                }
1356
1.30k
                case Fragment::AFTER: {
1357
1.30k
                    return {INVALID, ctx.CheckAfter(node.k) ? EMPTY : INVALID};
1358
372
                }
1359
504
                case Fragment::SHA256: {
1360
504
                    std::vector<unsigned char> preimage;
1361
504
                    Availability avail = ctx.SatSHA256(node.data, preimage);
1362
504
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1363
372
                }
1364
210
                case Fragment::RIPEMD160: {
1365
210
                    std::vector<unsigned char> preimage;
1366
210
                    Availability avail = ctx.SatRIPEMD160(node.data, preimage);
1367
210
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1368
372
                }
1369
372
                case Fragment::HASH256: {
1370
372
                    std::vector<unsigned char> preimage;
1371
372
                    Availability avail = ctx.SatHASH256(node.data, preimage);
1372
372
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1373
372
                }
1374
156
                case Fragment::HASH160: {
1375
156
                    std::vector<unsigned char> preimage;
1376
156
                    Availability avail = ctx.SatHASH160(node.data, preimage);
1377
156
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1378
372
                }
1379
1.32k
                case Fragment::AND_V: {
1380
1.32k
                    auto& x = subres[0], &y = subres[1];
1381
                    // As the dissatisfaction here only consist of a single option, it doesn't
1382
                    // actually need to be listed (it's not required for reasoning about malleability of
1383
                    // other options), and is never required (no valid miniscript relies on the ability
1384
                    // to satisfy the type V left subexpression). It's still listed here for
1385
                    // completeness, as a hypothetical (not currently implemented) satisfier that doesn't
1386
                    // care about malleability might in some cases prefer it still.
1387
1.32k
                    return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
1388
372
                }
1389
407k
                case Fragment::AND_B: {
1390
407k
                    auto& x = subres[0], &y = subres[1];
1391
                    // Note that it is not strictly necessary to mark the 2nd and 3rd dissatisfaction here
1392
                    // as malleable. While they are definitely malleable, they are also non-canonical due
1393
                    // to the guaranteed existence of a no-signature other dissatisfaction (the 1st)
1394
                    // option. Because of that, the 2nd and 3rd option will never be chosen, even if they
1395
                    // weren't marked as malleable.
1396
407k
                    return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
1397
372
                }
1398
144
                case Fragment::OR_B: {
1399
144
                    auto& x = subres[0], &z = subres[1];
1400
                    // The (sat(Z) sat(X)) solution is overcomplete (attacker can change either into dsat).
1401
144
                    return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
1402
372
                }
1403
90
                case Fragment::OR_C: {
1404
90
                    auto& x = subres[0], &z = subres[1];
1405
90
                    return {INVALID, std::move(x.sat) | (z.sat + x.nsat)};
1406
372
                }
1407
312
                case Fragment::OR_D: {
1408
312
                    auto& x = subres[0], &z = subres[1];
1409
312
                    return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
1410
372
                }
1411
1.59k
                case Fragment::OR_I: {
1412
1.59k
                    auto& x = subres[0], &z = subres[1];
1413
1.59k
                    return {(x.nsat + ONE) | (z.nsat + ZERO), (x.sat + ONE) | (z.sat + ZERO)};
1414
372
                }
1415
672
                case Fragment::ANDOR: {
1416
672
                    auto& x = subres[0], &y = subres[1], &z = subres[2];
1417
672
                    return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
1418
372
                }
1419
408k
                case Fragment::WRAP_A:
1420
408k
                case Fragment::WRAP_S:
1421
783k
                case Fragment::WRAP_C:
1422
783k
                case Fragment::WRAP_N:
1423
783k
                    return std::move(subres[0]);
1424
96
                case Fragment::WRAP_D: {
1425
96
                    auto &x = subres[0];
1426
96
                    return {ZERO, x.sat + ONE};
1427
783k
                }
1428
198
                case Fragment::WRAP_J: {
1429
198
                    auto &x = subres[0];
1430
                    // If a dissatisfaction with a nonzero top stack element exists, an alternative dissatisfaction exists.
1431
                    // As the dissatisfaction logic currently doesn't keep track of this nonzeroness property, and thus even
1432
                    // if a dissatisfaction with a top zero element is found, we don't know whether another one with a
1433
                    // nonzero top stack element exists. Make the conservative assumption that whenever the subexpression is weakly
1434
                    // dissatisfiable, this alternative dissatisfaction exists and leads to malleability.
1435
198
                    return {InputStack(ZERO).SetMalleable(x.nsat.available != Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
1436
783k
                }
1437
1.62k
                case Fragment::WRAP_V: {
1438
1.62k
                    auto &x = subres[0];
1439
1.62k
                    return {INVALID, std::move(x.sat)};
1440
783k
                }
1441
1.50k
                case Fragment::JUST_0: return {EMPTY, INVALID};
1442
972
                case Fragment::JUST_1: return {INVALID, EMPTY};
1443
1.61M
            }
1444
1.61M
            assert(false);
1445
0
            return {INVALID, INVALID};
1446
0
        };
miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)::operator()(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>) const
Line
Count
Source
1252
1.98M
        auto helper = [&ctx](const Node& node, std::span<InputResult> subres) -> InputResult {
1253
1.98M
            switch (node.fragment) {
1254
3.37k
                case Fragment::PK_K: {
1255
3.37k
                    std::vector<unsigned char> sig;
1256
3.37k
                    Availability avail = ctx.Sign(node.keys[0], sig);
1257
3.37k
                    return {ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
1258
0
                }
1259
336
                case Fragment::PK_H: {
1260
336
                    std::vector<unsigned char> key = ctx.ToPKBytes(node.keys[0]), sig;
1261
336
                    Availability avail = ctx.Sign(node.keys[0], sig);
1262
336
                    return {ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
1263
0
                }
1264
784
                case Fragment::MULTI_A: {
1265
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1266
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1267
784
                    std::vector<InputStack> sats = Vector(EMPTY);
1268
90.3k
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1269
                        // Get the signature for the i'th key in reverse order (the signature for the first key needs to
1270
                        // be at the top of the stack, contrary to CHECKMULTISIG's satisfaction).
1271
89.5k
                        std::vector<unsigned char> sig;
1272
89.5k
                        Availability avail = ctx.Sign(node.keys[node.keys.size() - 1 - i], sig);
1273
                        // Compute signature stack for just this key.
1274
89.5k
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1275
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1276
                        // next_sats[j] are equal to either the existing sats[j] + ZERO, or sats[j-1] plus a signature
1277
                        // for the current (i'th) key. The very last element needs all signatures filled.
1278
89.5k
                        std::vector<InputStack> next_sats;
1279
89.5k
                        next_sats.push_back(sats[0] + ZERO);
1280
43.9M
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + ZERO) | (std::move(sats[j - 1]) + sat));
1281
89.5k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1282
                        // Switch over.
1283
89.5k
                        sats = std::move(next_sats);
1284
89.5k
                    }
1285
                    // The dissatisfaction consists of as many empty vectors as there are keys, which is the same as
1286
                    // satisfying 0 keys.
1287
784
                    auto& nsat{sats[0]};
1288
784
                    CHECK_NONFATAL(node.k != 0);
1289
784
                    assert(node.k < sats.size());
1290
784
                    return {std::move(nsat), std::move(sats[node.k])};
1291
784
                }
1292
0
                case Fragment::MULTI: {
1293
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1294
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1295
                    // sats[0] starts off being {0}, due to the CHECKMULTISIG bug that pops off one element too many.
1296
0
                    std::vector<InputStack> sats = Vector(ZERO);
1297
0
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1298
0
                        std::vector<unsigned char> sig;
1299
0
                        Availability avail = ctx.Sign(node.keys[i], sig);
1300
                        // Compute signature stack for just the i'th key.
1301
0
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1302
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1303
                        // next_sats[j] are equal to either the existing sats[j], or sats[j-1] plus a signature for the
1304
                        // current (i'th) key. The very last element needs all signatures filled.
1305
0
                        std::vector<InputStack> next_sats;
1306
0
                        next_sats.push_back(sats[0]);
1307
0
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
1308
0
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1309
                        // Switch over.
1310
0
                        sats = std::move(next_sats);
1311
0
                    }
1312
                    // The dissatisfaction consists of k+1 stack elements all equal to 0.
1313
0
                    InputStack nsat = ZERO;
1314
0
                    for (size_t i = 0; i < node.k; ++i) nsat = std::move(nsat) + ZERO;
1315
0
                    assert(node.k < sats.size());
1316
0
                    return {std::move(nsat), std::move(sats[node.k])};
1317
0
                }
1318
22
                case Fragment::THRESH: {
1319
                    // sats[k] represents the best stack that satisfies k out of the *last* i subexpressions.
1320
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1321
                    // sats[0] starts off empty.
1322
22
                    std::vector<InputStack> sats = Vector(EMPTY);
1323
88
                    for (size_t i = 0; i < subres.size(); ++i) {
1324
                        // Introduce an alias for the i'th last satisfaction/dissatisfaction.
1325
66
                        auto& res = subres[subres.size() - i - 1];
1326
                        // Compute the next sats vector: next_sats[0] is sats[0] plus res.nsat (thus containing all dissatisfactions
1327
                        // so far. next_sats[j] is either sats[j] + res.nsat (reusing j earlier satisfactions) or sats[j-1] + res.sat
1328
                        // (reusing j-1 earlier satisfactions plus a new one). The very last next_sats[j] is all satisfactions.
1329
66
                        std::vector<InputStack> next_sats;
1330
66
                        next_sats.push_back(sats[0] + res.nsat);
1331
132
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + res.nsat) | (std::move(sats[j - 1]) + res.sat));
1332
66
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
1333
                        // Switch over.
1334
66
                        sats = std::move(next_sats);
1335
66
                    }
1336
                    // At this point, sats[k].sat is the best satisfaction for the overall thresh() node. The best dissatisfaction
1337
                    // is computed by gathering all sats[i].nsat for i != k.
1338
22
                    InputStack nsat = INVALID;
1339
110
                    for (size_t i = 0; i < sats.size(); ++i) {
1340
                        // i==k is the satisfaction; i==0 is the canonical dissatisfaction;
1341
                        // the rest are non-canonical (a no-signature dissatisfaction - the i=0
1342
                        // form - is always available) and malleable (due to overcompleteness).
1343
                        // Marking the solutions malleable here is not strictly necessary, as they
1344
                        // should already never be picked in non-malleable solutions due to the
1345
                        // availability of the i=0 form.
1346
88
                        if (i != 0 && i != node.k) sats[i].SetMalleable().SetNonCanon();
1347
                        // Include all dissatisfactions (even these non-canonical ones) in nsat.
1348
88
                        if (i != node.k) nsat = std::move(nsat) | std::move(sats[i]);
1349
88
                    }
1350
22
                    assert(node.k < sats.size());
1351
22
                    return {std::move(nsat), std::move(sats[node.k])};
1352
22
                }
1353
51
                case Fragment::OLDER: {
1354
51
                    return {INVALID, ctx.CheckOlder(node.k) ? EMPTY : INVALID};
1355
22
                }
1356
789
                case Fragment::AFTER: {
1357
789
                    return {INVALID, ctx.CheckAfter(node.k) ? EMPTY : INVALID};
1358
22
                }
1359
0
                case Fragment::SHA256: {
1360
0
                    std::vector<unsigned char> preimage;
1361
0
                    Availability avail = ctx.SatSHA256(node.data, preimage);
1362
0
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1363
22
                }
1364
0
                case Fragment::RIPEMD160: {
1365
0
                    std::vector<unsigned char> preimage;
1366
0
                    Availability avail = ctx.SatRIPEMD160(node.data, preimage);
1367
0
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1368
22
                }
1369
12
                case Fragment::HASH256: {
1370
12
                    std::vector<unsigned char> preimage;
1371
12
                    Availability avail = ctx.SatHASH256(node.data, preimage);
1372
12
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1373
22
                }
1374
0
                case Fragment::HASH160: {
1375
0
                    std::vector<unsigned char> preimage;
1376
0
                    Availability avail = ctx.SatHASH160(node.data, preimage);
1377
0
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1378
22
                }
1379
880
                case Fragment::AND_V: {
1380
880
                    auto& x = subres[0], &y = subres[1];
1381
                    // As the dissatisfaction here only consist of a single option, it doesn't
1382
                    // actually need to be listed (it's not required for reasoning about malleability of
1383
                    // other options), and is never required (no valid miniscript relies on the ability
1384
                    // to satisfy the type V left subexpression). It's still listed here for
1385
                    // completeness, as a hypothetical (not currently implemented) satisfier that doesn't
1386
                    // care about malleability might in some cases prefer it still.
1387
880
                    return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
1388
22
                }
1389
64
                case Fragment::AND_B: {
1390
64
                    auto& x = subres[0], &y = subres[1];
1391
                    // Note that it is not strictly necessary to mark the 2nd and 3rd dissatisfaction here
1392
                    // as malleable. While they are definitely malleable, they are also non-canonical due
1393
                    // to the guaranteed existence of a no-signature other dissatisfaction (the 1st)
1394
                    // option. Because of that, the 2nd and 3rd option will never be chosen, even if they
1395
                    // weren't marked as malleable.
1396
64
                    return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
1397
22
                }
1398
28
                case Fragment::OR_B: {
1399
28
                    auto& x = subres[0], &z = subres[1];
1400
                    // The (sat(Z) sat(X)) solution is overcomplete (attacker can change either into dsat).
1401
28
                    return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
1402
22
                }
1403
0
                case Fragment::OR_C: {
1404
0
                    auto& x = subres[0], &z = subres[1];
1405
0
                    return {INVALID, std::move(x.sat) | (z.sat + x.nsat)};
1406
22
                }
1407
0
                case Fragment::OR_D: {
1408
0
                    auto& x = subres[0], &z = subres[1];
1409
0
                    return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
1410
22
                }
1411
0
                case Fragment::OR_I: {
1412
0
                    auto& x = subres[0], &z = subres[1];
1413
0
                    return {(x.nsat + ONE) | (z.nsat + ZERO), (x.sat + ONE) | (z.sat + ZERO)};
1414
22
                }
1415
0
                case Fragment::ANDOR: {
1416
0
                    auto& x = subres[0], &y = subres[1], &z = subres[2];
1417
0
                    return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
1418
22
                }
1419
86
                case Fragment::WRAP_A:
1420
136
                case Fragment::WRAP_S:
1421
3.84k
                case Fragment::WRAP_C:
1422
1.98M
                case Fragment::WRAP_N:
1423
1.98M
                    return std::move(subres[0]);
1424
6
                case Fragment::WRAP_D: {
1425
6
                    auto &x = subres[0];
1426
6
                    return {ZERO, x.sat + ONE};
1427
3.84k
                }
1428
0
                case Fragment::WRAP_J: {
1429
0
                    auto &x = subres[0];
1430
                    // If a dissatisfaction with a nonzero top stack element exists, an alternative dissatisfaction exists.
1431
                    // As the dissatisfaction logic currently doesn't keep track of this nonzeroness property, and thus even
1432
                    // if a dissatisfaction with a top zero element is found, we don't know whether another one with a
1433
                    // nonzero top stack element exists. Make the conservative assumption that whenever the subexpression is weakly
1434
                    // dissatisfiable, this alternative dissatisfaction exists and leads to malleability.
1435
0
                    return {InputStack(ZERO).SetMalleable(x.nsat.available != Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
1436
3.84k
                }
1437
886
                case Fragment::WRAP_V: {
1438
886
                    auto &x = subres[0];
1439
886
                    return {INVALID, std::move(x.sat)};
1440
3.84k
                }
1441
0
                case Fragment::JUST_0: return {EMPTY, INVALID};
1442
0
                case Fragment::JUST_1: return {INVALID, EMPTY};
1443
1.98M
            }
1444
1.98M
            assert(false);
1445
0
            return {INVALID, INVALID};
1446
0
        };
miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)::operator()(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>) const
Line
Count
Source
1252
3.13k
        auto helper = [&ctx](const Node& node, std::span<InputResult> subres) -> InputResult {
1253
3.13k
            switch (node.fragment) {
1254
459
                case Fragment::PK_K: {
1255
459
                    std::vector<unsigned char> sig;
1256
459
                    Availability avail = ctx.Sign(node.keys[0], sig);
1257
459
                    return {ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
1258
0
                }
1259
69
                case Fragment::PK_H: {
1260
69
                    std::vector<unsigned char> key = ctx.ToPKBytes(node.keys[0]), sig;
1261
69
                    Availability avail = ctx.Sign(node.keys[0], sig);
1262
69
                    return {ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
1263
0
                }
1264
0
                case Fragment::MULTI_A: {
1265
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1266
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1267
0
                    std::vector<InputStack> sats = Vector(EMPTY);
1268
0
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1269
                        // Get the signature for the i'th key in reverse order (the signature for the first key needs to
1270
                        // be at the top of the stack, contrary to CHECKMULTISIG's satisfaction).
1271
0
                        std::vector<unsigned char> sig;
1272
0
                        Availability avail = ctx.Sign(node.keys[node.keys.size() - 1 - i], sig);
1273
                        // Compute signature stack for just this key.
1274
0
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1275
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1276
                        // next_sats[j] are equal to either the existing sats[j] + ZERO, or sats[j-1] plus a signature
1277
                        // for the current (i'th) key. The very last element needs all signatures filled.
1278
0
                        std::vector<InputStack> next_sats;
1279
0
                        next_sats.push_back(sats[0] + ZERO);
1280
0
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + ZERO) | (std::move(sats[j - 1]) + sat));
1281
0
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1282
                        // Switch over.
1283
0
                        sats = std::move(next_sats);
1284
0
                    }
1285
                    // The dissatisfaction consists of as many empty vectors as there are keys, which is the same as
1286
                    // satisfying 0 keys.
1287
0
                    auto& nsat{sats[0]};
1288
0
                    CHECK_NONFATAL(node.k != 0);
1289
0
                    assert(node.k < sats.size());
1290
0
                    return {std::move(nsat), std::move(sats[node.k])};
1291
0
                }
1292
24
                case Fragment::MULTI: {
1293
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1294
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1295
                    // sats[0] starts off being {0}, due to the CHECKMULTISIG bug that pops off one element too many.
1296
24
                    std::vector<InputStack> sats = Vector(ZERO);
1297
72
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1298
48
                        std::vector<unsigned char> sig;
1299
48
                        Availability avail = ctx.Sign(node.keys[i], sig);
1300
                        // Compute signature stack for just the i'th key.
1301
48
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1302
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1303
                        // next_sats[j] are equal to either the existing sats[j], or sats[j-1] plus a signature for the
1304
                        // current (i'th) key. The very last element needs all signatures filled.
1305
48
                        std::vector<InputStack> next_sats;
1306
48
                        next_sats.push_back(sats[0]);
1307
72
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
1308
48
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1309
                        // Switch over.
1310
48
                        sats = std::move(next_sats);
1311
48
                    }
1312
                    // The dissatisfaction consists of k+1 stack elements all equal to 0.
1313
24
                    InputStack nsat = ZERO;
1314
48
                    for (size_t i = 0; i < node.k; ++i) nsat = std::move(nsat) + ZERO;
1315
24
                    assert(node.k < sats.size());
1316
24
                    return {std::move(nsat), std::move(sats[node.k])};
1317
24
                }
1318
112
                case Fragment::THRESH: {
1319
                    // sats[k] represents the best stack that satisfies k out of the *last* i subexpressions.
1320
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1321
                    // sats[0] starts off empty.
1322
112
                    std::vector<InputStack> sats = Vector(EMPTY);
1323
710
                    for (size_t i = 0; i < subres.size(); ++i) {
1324
                        // Introduce an alias for the i'th last satisfaction/dissatisfaction.
1325
598
                        auto& res = subres[subres.size() - i - 1];
1326
                        // Compute the next sats vector: next_sats[0] is sats[0] plus res.nsat (thus containing all dissatisfactions
1327
                        // so far. next_sats[j] is either sats[j] + res.nsat (reusing j earlier satisfactions) or sats[j-1] + res.sat
1328
                        // (reusing j-1 earlier satisfactions plus a new one). The very last next_sats[j] is all satisfactions.
1329
598
                        std::vector<InputStack> next_sats;
1330
598
                        next_sats.push_back(sats[0] + res.nsat);
1331
2.18k
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + res.nsat) | (std::move(sats[j - 1]) + res.sat));
1332
598
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
1333
                        // Switch over.
1334
598
                        sats = std::move(next_sats);
1335
598
                    }
1336
                    // At this point, sats[k].sat is the best satisfaction for the overall thresh() node. The best dissatisfaction
1337
                    // is computed by gathering all sats[i].nsat for i != k.
1338
112
                    InputStack nsat = INVALID;
1339
822
                    for (size_t i = 0; i < sats.size(); ++i) {
1340
                        // i==k is the satisfaction; i==0 is the canonical dissatisfaction;
1341
                        // the rest are non-canonical (a no-signature dissatisfaction - the i=0
1342
                        // form - is always available) and malleable (due to overcompleteness).
1343
                        // Marking the solutions malleable here is not strictly necessary, as they
1344
                        // should already never be picked in non-malleable solutions due to the
1345
                        // availability of the i=0 form.
1346
710
                        if (i != 0 && i != node.k) sats[i].SetMalleable().SetNonCanon();
1347
                        // Include all dissatisfactions (even these non-canonical ones) in nsat.
1348
710
                        if (i != node.k) nsat = std::move(nsat) | std::move(sats[i]);
1349
710
                    }
1350
112
                    assert(node.k < sats.size());
1351
112
                    return {std::move(nsat), std::move(sats[node.k])};
1352
112
                }
1353
58
                case Fragment::OLDER: {
1354
58
                    return {INVALID, ctx.CheckOlder(node.k) ? EMPTY : INVALID};
1355
112
                }
1356
244
                case Fragment::AFTER: {
1357
244
                    return {INVALID, ctx.CheckAfter(node.k) ? EMPTY : INVALID};
1358
112
                }
1359
17
                case Fragment::SHA256: {
1360
17
                    std::vector<unsigned char> preimage;
1361
17
                    Availability avail = ctx.SatSHA256(node.data, preimage);
1362
17
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1363
112
                }
1364
12
                case Fragment::RIPEMD160: {
1365
12
                    std::vector<unsigned char> preimage;
1366
12
                    Availability avail = ctx.SatRIPEMD160(node.data, preimage);
1367
12
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1368
112
                }
1369
12
                case Fragment::HASH256: {
1370
12
                    std::vector<unsigned char> preimage;
1371
12
                    Availability avail = ctx.SatHASH256(node.data, preimage);
1372
12
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1373
112
                }
1374
12
                case Fragment::HASH160: {
1375
12
                    std::vector<unsigned char> preimage;
1376
12
                    Availability avail = ctx.SatHASH160(node.data, preimage);
1377
12
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1378
112
                }
1379
102
                case Fragment::AND_V: {
1380
102
                    auto& x = subres[0], &y = subres[1];
1381
                    // As the dissatisfaction here only consist of a single option, it doesn't
1382
                    // actually need to be listed (it's not required for reasoning about malleability of
1383
                    // other options), and is never required (no valid miniscript relies on the ability
1384
                    // to satisfy the type V left subexpression). It's still listed here for
1385
                    // completeness, as a hypothetical (not currently implemented) satisfier that doesn't
1386
                    // care about malleability might in some cases prefer it still.
1387
102
                    return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
1388
112
                }
1389
36
                case Fragment::AND_B: {
1390
36
                    auto& x = subres[0], &y = subres[1];
1391
                    // Note that it is not strictly necessary to mark the 2nd and 3rd dissatisfaction here
1392
                    // as malleable. While they are definitely malleable, they are also non-canonical due
1393
                    // to the guaranteed existence of a no-signature other dissatisfaction (the 1st)
1394
                    // option. Because of that, the 2nd and 3rd option will never be chosen, even if they
1395
                    // weren't marked as malleable.
1396
36
                    return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
1397
112
                }
1398
0
                case Fragment::OR_B: {
1399
0
                    auto& x = subres[0], &z = subres[1];
1400
                    // The (sat(Z) sat(X)) solution is overcomplete (attacker can change either into dsat).
1401
0
                    return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
1402
112
                }
1403
0
                case Fragment::OR_C: {
1404
0
                    auto& x = subres[0], &z = subres[1];
1405
0
                    return {INVALID, std::move(x.sat) | (z.sat + x.nsat)};
1406
112
                }
1407
5
                case Fragment::OR_D: {
1408
5
                    auto& x = subres[0], &z = subres[1];
1409
5
                    return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
1410
112
                }
1411
230
                case Fragment::OR_I: {
1412
230
                    auto& x = subres[0], &z = subres[1];
1413
230
                    return {(x.nsat + ONE) | (z.nsat + ZERO), (x.sat + ONE) | (z.sat + ZERO)};
1414
112
                }
1415
38
                case Fragment::ANDOR: {
1416
38
                    auto& x = subres[0], &y = subres[1], &z = subres[2];
1417
38
                    return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
1418
112
                }
1419
75
                case Fragment::WRAP_A:
1420
522
                case Fragment::WRAP_S:
1421
1.04k
                case Fragment::WRAP_C:
1422
1.31k
                case Fragment::WRAP_N:
1423
1.31k
                    return std::move(subres[0]);
1424
23
                case Fragment::WRAP_D: {
1425
23
                    auto &x = subres[0];
1426
23
                    return {ZERO, x.sat + ONE};
1427
1.04k
                }
1428
0
                case Fragment::WRAP_J: {
1429
0
                    auto &x = subres[0];
1430
                    // If a dissatisfaction with a nonzero top stack element exists, an alternative dissatisfaction exists.
1431
                    // As the dissatisfaction logic currently doesn't keep track of this nonzeroness property, and thus even
1432
                    // if a dissatisfaction with a top zero element is found, we don't know whether another one with a
1433
                    // nonzero top stack element exists. Make the conservative assumption that whenever the subexpression is weakly
1434
                    // dissatisfiable, this alternative dissatisfaction exists and leads to malleability.
1435
0
                    return {InputStack(ZERO).SetMalleable(x.nsat.available != Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
1436
1.04k
                }
1437
125
                case Fragment::WRAP_V: {
1438
125
                    auto &x = subres[0];
1439
125
                    return {INVALID, std::move(x.sat)};
1440
1.04k
                }
1441
243
                case Fragment::JUST_0: return {EMPTY, INVALID};
1442
0
                case Fragment::JUST_1: return {INVALID, EMPTY};
1443
3.13k
            }
1444
3.13k
            assert(false);
1445
0
            return {INVALID, INVALID};
1446
0
        };
1447
1448
3.60M
        auto tester = [&helper](const Node& node, std::span<InputResult> subres) -> InputResult {
1449
3.60M
            auto ret = helper(node, subres);
1450
1451
            // Do a consistency check between the satisfaction code and the type checker
1452
            // (the actual satisfaction code in ProduceInputHelper does not use GetType)
1453
1454
            // For 'z' nodes, available satisfactions/dissatisfactions must have stack size 0.
1455
3.60M
            if (node.GetType() << "z"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 0);
1456
3.60M
            if (node.GetType() << "z"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 0);
1457
1458
            // For 'o' nodes, available satisfactions/dissatisfactions must have stack size 1.
1459
3.60M
            if (node.GetType() << "o"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 1);
1460
3.60M
            if (node.GetType() << "o"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 1);
1461
1462
            // For 'n' nodes, available satisfactions/dissatisfactions must have stack size 1 or larger. For satisfactions,
1463
            // the top element cannot be 0.
1464
3.60M
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() >= 1);
1465
3.60M
            if (node.GetType() << "n"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() >= 1);
1466
3.60M
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.stack.back().empty());
1467
1468
            // For 'd' nodes, a dissatisfaction must exist, and they must not need a signature. If it is non-malleable,
1469
            // it must be canonical.
1470
3.60M
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1471
3.60M
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(!ret.nsat.has_sig);
1472
3.60M
            if (node.GetType() << "d"_mst && !ret.nsat.malleable) CHECK_NONFATAL(!ret.nsat.non_canon);
1473
1474
            // For 'f'/'s' nodes, dissatisfactions/satisfactions must have a signature.
1475
3.60M
            if (node.GetType() << "f"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.has_sig);
1476
3.60M
            if (node.GetType() << "s"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.has_sig);
1477
1478
            // For non-malleable 'e' nodes, a non-malleable dissatisfaction must exist.
1479
3.60M
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1480
3.60M
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(!ret.nsat.malleable);
1481
1482
            // For 'm' nodes, if a satisfaction exists, it must be non-malleable.
1483
3.60M
            if (node.GetType() << "m"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.malleable);
1484
1485
            // If a non-malleable satisfaction exists, it must be canonical.
1486
3.60M
            if (ret.sat.available != Availability::NO && !ret.sat.malleable) CHECK_NONFATAL(!ret.sat.non_canon);
1487
1488
3.60M
            return ret;
1489
3.60M
        };
miniscript_tests.cpp:miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)::operator()(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>) const
Line
Count
Source
1448
1.61M
        auto tester = [&helper](const Node& node, std::span<InputResult> subres) -> InputResult {
1449
1.61M
            auto ret = helper(node, subres);
1450
1451
            // Do a consistency check between the satisfaction code and the type checker
1452
            // (the actual satisfaction code in ProduceInputHelper does not use GetType)
1453
1454
            // For 'z' nodes, available satisfactions/dissatisfactions must have stack size 0.
1455
1.61M
            if (node.GetType() << "z"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 0);
1456
1.61M
            if (node.GetType() << "z"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 0);
1457
1458
            // For 'o' nodes, available satisfactions/dissatisfactions must have stack size 1.
1459
1.61M
            if (node.GetType() << "o"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 1);
1460
1.61M
            if (node.GetType() << "o"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 1);
1461
1462
            // For 'n' nodes, available satisfactions/dissatisfactions must have stack size 1 or larger. For satisfactions,
1463
            // the top element cannot be 0.
1464
1.61M
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() >= 1);
1465
1.61M
            if (node.GetType() << "n"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() >= 1);
1466
1.61M
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.stack.back().empty());
1467
1468
            // For 'd' nodes, a dissatisfaction must exist, and they must not need a signature. If it is non-malleable,
1469
            // it must be canonical.
1470
1.61M
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1471
1.61M
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(!ret.nsat.has_sig);
1472
1.61M
            if (node.GetType() << "d"_mst && !ret.nsat.malleable) CHECK_NONFATAL(!ret.nsat.non_canon);
1473
1474
            // For 'f'/'s' nodes, dissatisfactions/satisfactions must have a signature.
1475
1.61M
            if (node.GetType() << "f"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.has_sig);
1476
1.61M
            if (node.GetType() << "s"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.has_sig);
1477
1478
            // For non-malleable 'e' nodes, a non-malleable dissatisfaction must exist.
1479
1.61M
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1480
1.61M
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(!ret.nsat.malleable);
1481
1482
            // For 'm' nodes, if a satisfaction exists, it must be non-malleable.
1483
1.61M
            if (node.GetType() << "m"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.malleable);
1484
1485
            // If a non-malleable satisfaction exists, it must be canonical.
1486
1.61M
            if (ret.sat.available != Availability::NO && !ret.sat.malleable) CHECK_NONFATAL(!ret.sat.non_canon);
1487
1488
1.61M
            return ret;
1489
1.61M
        };
miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const::'lambda0'(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)::operator()(miniscript::Node<XOnlyPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>) const
Line
Count
Source
1448
1.98M
        auto tester = [&helper](const Node& node, std::span<InputResult> subres) -> InputResult {
1449
1.98M
            auto ret = helper(node, subres);
1450
1451
            // Do a consistency check between the satisfaction code and the type checker
1452
            // (the actual satisfaction code in ProduceInputHelper does not use GetType)
1453
1454
            // For 'z' nodes, available satisfactions/dissatisfactions must have stack size 0.
1455
1.98M
            if (node.GetType() << "z"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 0);
1456
1.98M
            if (node.GetType() << "z"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 0);
1457
1458
            // For 'o' nodes, available satisfactions/dissatisfactions must have stack size 1.
1459
1.98M
            if (node.GetType() << "o"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 1);
1460
1.98M
            if (node.GetType() << "o"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 1);
1461
1462
            // For 'n' nodes, available satisfactions/dissatisfactions must have stack size 1 or larger. For satisfactions,
1463
            // the top element cannot be 0.
1464
1.98M
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() >= 1);
1465
1.98M
            if (node.GetType() << "n"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() >= 1);
1466
1.98M
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.stack.back().empty());
1467
1468
            // For 'd' nodes, a dissatisfaction must exist, and they must not need a signature. If it is non-malleable,
1469
            // it must be canonical.
1470
1.98M
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1471
1.98M
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(!ret.nsat.has_sig);
1472
1.98M
            if (node.GetType() << "d"_mst && !ret.nsat.malleable) CHECK_NONFATAL(!ret.nsat.non_canon);
1473
1474
            // For 'f'/'s' nodes, dissatisfactions/satisfactions must have a signature.
1475
1.98M
            if (node.GetType() << "f"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.has_sig);
1476
1.98M
            if (node.GetType() << "s"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.has_sig);
1477
1478
            // For non-malleable 'e' nodes, a non-malleable dissatisfaction must exist.
1479
1.98M
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1480
1.98M
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(!ret.nsat.malleable);
1481
1482
            // For 'm' nodes, if a satisfaction exists, it must be non-malleable.
1483
1.98M
            if (node.GetType() << "m"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.malleable);
1484
1485
            // If a non-malleable satisfaction exists, it must be canonical.
1486
1.98M
            if (ret.sat.available != Availability::NO && !ret.sat.malleable) CHECK_NONFATAL(!ret.sat.non_canon);
1487
1488
1.98M
            return ret;
1489
1.98M
        };
miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const::'lambda0'(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>)::operator()(miniscript::Node<CPubKey> const&, std::span<miniscript::internal::InputResult, 18446744073709551615ul>) const
Line
Count
Source
1448
3.13k
        auto tester = [&helper](const Node& node, std::span<InputResult> subres) -> InputResult {
1449
3.13k
            auto ret = helper(node, subres);
1450
1451
            // Do a consistency check between the satisfaction code and the type checker
1452
            // (the actual satisfaction code in ProduceInputHelper does not use GetType)
1453
1454
            // For 'z' nodes, available satisfactions/dissatisfactions must have stack size 0.
1455
3.13k
            if (node.GetType() << "z"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 0);
1456
3.13k
            if (node.GetType() << "z"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 0);
1457
1458
            // For 'o' nodes, available satisfactions/dissatisfactions must have stack size 1.
1459
3.13k
            if (node.GetType() << "o"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 1);
1460
3.13k
            if (node.GetType() << "o"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 1);
1461
1462
            // For 'n' nodes, available satisfactions/dissatisfactions must have stack size 1 or larger. For satisfactions,
1463
            // the top element cannot be 0.
1464
3.13k
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() >= 1);
1465
3.13k
            if (node.GetType() << "n"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() >= 1);
1466
3.13k
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.stack.back().empty());
1467
1468
            // For 'd' nodes, a dissatisfaction must exist, and they must not need a signature. If it is non-malleable,
1469
            // it must be canonical.
1470
3.13k
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1471
3.13k
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(!ret.nsat.has_sig);
1472
3.13k
            if (node.GetType() << "d"_mst && !ret.nsat.malleable) CHECK_NONFATAL(!ret.nsat.non_canon);
1473
1474
            // For 'f'/'s' nodes, dissatisfactions/satisfactions must have a signature.
1475
3.13k
            if (node.GetType() << "f"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.has_sig);
1476
3.13k
            if (node.GetType() << "s"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.has_sig);
1477
1478
            // For non-malleable 'e' nodes, a non-malleable dissatisfaction must exist.
1479
3.13k
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1480
3.13k
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(!ret.nsat.malleable);
1481
1482
            // For 'm' nodes, if a satisfaction exists, it must be non-malleable.
1483
3.13k
            if (node.GetType() << "m"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.malleable);
1484
1485
            // If a non-malleable satisfaction exists, it must be canonical.
1486
3.13k
            if (ret.sat.available != Availability::NO && !ret.sat.malleable) CHECK_NONFATAL(!ret.sat.non_canon);
1487
1488
3.13k
            return ret;
1489
3.13k
        };
1490
1491
9.36k
        return TreeEval<InputResult>(tester);
1492
9.36k
    }
miniscript_tests.cpp:miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const
Line
Count
Source
1247
4.82k
    internal::InputResult ProduceInput(const Ctx& ctx) const {
1248
4.82k
        using namespace internal;
1249
1250
        // Internal function which is invoked for every tree node, constructing satisfaction/dissatisfactions
1251
        // given those of its subnodes.
1252
4.82k
        auto helper = [&ctx](const Node& node, std::span<InputResult> subres) -> InputResult {
1253
4.82k
            switch (node.fragment) {
1254
4.82k
                case Fragment::PK_K: {
1255
4.82k
                    std::vector<unsigned char> sig;
1256
4.82k
                    Availability avail = ctx.Sign(node.keys[0], sig);
1257
4.82k
                    return {ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
1258
4.82k
                }
1259
4.82k
                case Fragment::PK_H: {
1260
4.82k
                    std::vector<unsigned char> key = ctx.ToPKBytes(node.keys[0]), sig;
1261
4.82k
                    Availability avail = ctx.Sign(node.keys[0], sig);
1262
4.82k
                    return {ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
1263
4.82k
                }
1264
4.82k
                case Fragment::MULTI_A: {
1265
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1266
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1267
4.82k
                    std::vector<InputStack> sats = Vector(EMPTY);
1268
4.82k
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1269
                        // Get the signature for the i'th key in reverse order (the signature for the first key needs to
1270
                        // be at the top of the stack, contrary to CHECKMULTISIG's satisfaction).
1271
4.82k
                        std::vector<unsigned char> sig;
1272
4.82k
                        Availability avail = ctx.Sign(node.keys[node.keys.size() - 1 - i], sig);
1273
                        // Compute signature stack for just this key.
1274
4.82k
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1275
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1276
                        // next_sats[j] are equal to either the existing sats[j] + ZERO, or sats[j-1] plus a signature
1277
                        // for the current (i'th) key. The very last element needs all signatures filled.
1278
4.82k
                        std::vector<InputStack> next_sats;
1279
4.82k
                        next_sats.push_back(sats[0] + ZERO);
1280
4.82k
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + ZERO) | (std::move(sats[j - 1]) + sat));
1281
4.82k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1282
                        // Switch over.
1283
4.82k
                        sats = std::move(next_sats);
1284
4.82k
                    }
1285
                    // The dissatisfaction consists of as many empty vectors as there are keys, which is the same as
1286
                    // satisfying 0 keys.
1287
4.82k
                    auto& nsat{sats[0]};
1288
4.82k
                    CHECK_NONFATAL(node.k != 0);
1289
4.82k
                    assert(node.k < sats.size());
1290
4.82k
                    return {std::move(nsat), std::move(sats[node.k])};
1291
4.82k
                }
1292
4.82k
                case Fragment::MULTI: {
1293
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1294
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1295
                    // sats[0] starts off being {0}, due to the CHECKMULTISIG bug that pops off one element too many.
1296
4.82k
                    std::vector<InputStack> sats = Vector(ZERO);
1297
4.82k
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1298
4.82k
                        std::vector<unsigned char> sig;
1299
4.82k
                        Availability avail = ctx.Sign(node.keys[i], sig);
1300
                        // Compute signature stack for just the i'th key.
1301
4.82k
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1302
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1303
                        // next_sats[j] are equal to either the existing sats[j], or sats[j-1] plus a signature for the
1304
                        // current (i'th) key. The very last element needs all signatures filled.
1305
4.82k
                        std::vector<InputStack> next_sats;
1306
4.82k
                        next_sats.push_back(sats[0]);
1307
4.82k
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
1308
4.82k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1309
                        // Switch over.
1310
4.82k
                        sats = std::move(next_sats);
1311
4.82k
                    }
1312
                    // The dissatisfaction consists of k+1 stack elements all equal to 0.
1313
4.82k
                    InputStack nsat = ZERO;
1314
4.82k
                    for (size_t i = 0; i < node.k; ++i) nsat = std::move(nsat) + ZERO;
1315
4.82k
                    assert(node.k < sats.size());
1316
4.82k
                    return {std::move(nsat), std::move(sats[node.k])};
1317
4.82k
                }
1318
4.82k
                case Fragment::THRESH: {
1319
                    // sats[k] represents the best stack that satisfies k out of the *last* i subexpressions.
1320
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1321
                    // sats[0] starts off empty.
1322
4.82k
                    std::vector<InputStack> sats = Vector(EMPTY);
1323
4.82k
                    for (size_t i = 0; i < subres.size(); ++i) {
1324
                        // Introduce an alias for the i'th last satisfaction/dissatisfaction.
1325
4.82k
                        auto& res = subres[subres.size() - i - 1];
1326
                        // Compute the next sats vector: next_sats[0] is sats[0] plus res.nsat (thus containing all dissatisfactions
1327
                        // so far. next_sats[j] is either sats[j] + res.nsat (reusing j earlier satisfactions) or sats[j-1] + res.sat
1328
                        // (reusing j-1 earlier satisfactions plus a new one). The very last next_sats[j] is all satisfactions.
1329
4.82k
                        std::vector<InputStack> next_sats;
1330
4.82k
                        next_sats.push_back(sats[0] + res.nsat);
1331
4.82k
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + res.nsat) | (std::move(sats[j - 1]) + res.sat));
1332
4.82k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
1333
                        // Switch over.
1334
4.82k
                        sats = std::move(next_sats);
1335
4.82k
                    }
1336
                    // At this point, sats[k].sat is the best satisfaction for the overall thresh() node. The best dissatisfaction
1337
                    // is computed by gathering all sats[i].nsat for i != k.
1338
4.82k
                    InputStack nsat = INVALID;
1339
4.82k
                    for (size_t i = 0; i < sats.size(); ++i) {
1340
                        // i==k is the satisfaction; i==0 is the canonical dissatisfaction;
1341
                        // the rest are non-canonical (a no-signature dissatisfaction - the i=0
1342
                        // form - is always available) and malleable (due to overcompleteness).
1343
                        // Marking the solutions malleable here is not strictly necessary, as they
1344
                        // should already never be picked in non-malleable solutions due to the
1345
                        // availability of the i=0 form.
1346
4.82k
                        if (i != 0 && i != node.k) sats[i].SetMalleable().SetNonCanon();
1347
                        // Include all dissatisfactions (even these non-canonical ones) in nsat.
1348
4.82k
                        if (i != node.k) nsat = std::move(nsat) | std::move(sats[i]);
1349
4.82k
                    }
1350
4.82k
                    assert(node.k < sats.size());
1351
4.82k
                    return {std::move(nsat), std::move(sats[node.k])};
1352
4.82k
                }
1353
4.82k
                case Fragment::OLDER: {
1354
4.82k
                    return {INVALID, ctx.CheckOlder(node.k) ? EMPTY : INVALID};
1355
4.82k
                }
1356
4.82k
                case Fragment::AFTER: {
1357
4.82k
                    return {INVALID, ctx.CheckAfter(node.k) ? EMPTY : INVALID};
1358
4.82k
                }
1359
4.82k
                case Fragment::SHA256: {
1360
4.82k
                    std::vector<unsigned char> preimage;
1361
4.82k
                    Availability avail = ctx.SatSHA256(node.data, preimage);
1362
4.82k
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1363
4.82k
                }
1364
4.82k
                case Fragment::RIPEMD160: {
1365
4.82k
                    std::vector<unsigned char> preimage;
1366
4.82k
                    Availability avail = ctx.SatRIPEMD160(node.data, preimage);
1367
4.82k
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1368
4.82k
                }
1369
4.82k
                case Fragment::HASH256: {
1370
4.82k
                    std::vector<unsigned char> preimage;
1371
4.82k
                    Availability avail = ctx.SatHASH256(node.data, preimage);
1372
4.82k
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1373
4.82k
                }
1374
4.82k
                case Fragment::HASH160: {
1375
4.82k
                    std::vector<unsigned char> preimage;
1376
4.82k
                    Availability avail = ctx.SatHASH160(node.data, preimage);
1377
4.82k
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1378
4.82k
                }
1379
4.82k
                case Fragment::AND_V: {
1380
4.82k
                    auto& x = subres[0], &y = subres[1];
1381
                    // As the dissatisfaction here only consist of a single option, it doesn't
1382
                    // actually need to be listed (it's not required for reasoning about malleability of
1383
                    // other options), and is never required (no valid miniscript relies on the ability
1384
                    // to satisfy the type V left subexpression). It's still listed here for
1385
                    // completeness, as a hypothetical (not currently implemented) satisfier that doesn't
1386
                    // care about malleability might in some cases prefer it still.
1387
4.82k
                    return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
1388
4.82k
                }
1389
4.82k
                case Fragment::AND_B: {
1390
4.82k
                    auto& x = subres[0], &y = subres[1];
1391
                    // Note that it is not strictly necessary to mark the 2nd and 3rd dissatisfaction here
1392
                    // as malleable. While they are definitely malleable, they are also non-canonical due
1393
                    // to the guaranteed existence of a no-signature other dissatisfaction (the 1st)
1394
                    // option. Because of that, the 2nd and 3rd option will never be chosen, even if they
1395
                    // weren't marked as malleable.
1396
4.82k
                    return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
1397
4.82k
                }
1398
4.82k
                case Fragment::OR_B: {
1399
4.82k
                    auto& x = subres[0], &z = subres[1];
1400
                    // The (sat(Z) sat(X)) solution is overcomplete (attacker can change either into dsat).
1401
4.82k
                    return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
1402
4.82k
                }
1403
4.82k
                case Fragment::OR_C: {
1404
4.82k
                    auto& x = subres[0], &z = subres[1];
1405
4.82k
                    return {INVALID, std::move(x.sat) | (z.sat + x.nsat)};
1406
4.82k
                }
1407
4.82k
                case Fragment::OR_D: {
1408
4.82k
                    auto& x = subres[0], &z = subres[1];
1409
4.82k
                    return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
1410
4.82k
                }
1411
4.82k
                case Fragment::OR_I: {
1412
4.82k
                    auto& x = subres[0], &z = subres[1];
1413
4.82k
                    return {(x.nsat + ONE) | (z.nsat + ZERO), (x.sat + ONE) | (z.sat + ZERO)};
1414
4.82k
                }
1415
4.82k
                case Fragment::ANDOR: {
1416
4.82k
                    auto& x = subres[0], &y = subres[1], &z = subres[2];
1417
4.82k
                    return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
1418
4.82k
                }
1419
4.82k
                case Fragment::WRAP_A:
1420
4.82k
                case Fragment::WRAP_S:
1421
4.82k
                case Fragment::WRAP_C:
1422
4.82k
                case Fragment::WRAP_N:
1423
4.82k
                    return std::move(subres[0]);
1424
4.82k
                case Fragment::WRAP_D: {
1425
4.82k
                    auto &x = subres[0];
1426
4.82k
                    return {ZERO, x.sat + ONE};
1427
4.82k
                }
1428
4.82k
                case Fragment::WRAP_J: {
1429
4.82k
                    auto &x = subres[0];
1430
                    // If a dissatisfaction with a nonzero top stack element exists, an alternative dissatisfaction exists.
1431
                    // As the dissatisfaction logic currently doesn't keep track of this nonzeroness property, and thus even
1432
                    // if a dissatisfaction with a top zero element is found, we don't know whether another one with a
1433
                    // nonzero top stack element exists. Make the conservative assumption that whenever the subexpression is weakly
1434
                    // dissatisfiable, this alternative dissatisfaction exists and leads to malleability.
1435
4.82k
                    return {InputStack(ZERO).SetMalleable(x.nsat.available != Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
1436
4.82k
                }
1437
4.82k
                case Fragment::WRAP_V: {
1438
4.82k
                    auto &x = subres[0];
1439
4.82k
                    return {INVALID, std::move(x.sat)};
1440
4.82k
                }
1441
4.82k
                case Fragment::JUST_0: return {EMPTY, INVALID};
1442
4.82k
                case Fragment::JUST_1: return {INVALID, EMPTY};
1443
4.82k
            }
1444
4.82k
            assert(false);
1445
4.82k
            return {INVALID, INVALID};
1446
4.82k
        };
1447
1448
4.82k
        auto tester = [&helper](const Node& node, std::span<InputResult> subres) -> InputResult {
1449
4.82k
            auto ret = helper(node, subres);
1450
1451
            // Do a consistency check between the satisfaction code and the type checker
1452
            // (the actual satisfaction code in ProduceInputHelper does not use GetType)
1453
1454
            // For 'z' nodes, available satisfactions/dissatisfactions must have stack size 0.
1455
4.82k
            if (node.GetType() << "z"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 0);
1456
4.82k
            if (node.GetType() << "z"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 0);
1457
1458
            // For 'o' nodes, available satisfactions/dissatisfactions must have stack size 1.
1459
4.82k
            if (node.GetType() << "o"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 1);
1460
4.82k
            if (node.GetType() << "o"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 1);
1461
1462
            // For 'n' nodes, available satisfactions/dissatisfactions must have stack size 1 or larger. For satisfactions,
1463
            // the top element cannot be 0.
1464
4.82k
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() >= 1);
1465
4.82k
            if (node.GetType() << "n"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() >= 1);
1466
4.82k
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.stack.back().empty());
1467
1468
            // For 'd' nodes, a dissatisfaction must exist, and they must not need a signature. If it is non-malleable,
1469
            // it must be canonical.
1470
4.82k
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1471
4.82k
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(!ret.nsat.has_sig);
1472
4.82k
            if (node.GetType() << "d"_mst && !ret.nsat.malleable) CHECK_NONFATAL(!ret.nsat.non_canon);
1473
1474
            // For 'f'/'s' nodes, dissatisfactions/satisfactions must have a signature.
1475
4.82k
            if (node.GetType() << "f"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.has_sig);
1476
4.82k
            if (node.GetType() << "s"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.has_sig);
1477
1478
            // For non-malleable 'e' nodes, a non-malleable dissatisfaction must exist.
1479
4.82k
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1480
4.82k
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(!ret.nsat.malleable);
1481
1482
            // For 'm' nodes, if a satisfaction exists, it must be non-malleable.
1483
4.82k
            if (node.GetType() << "m"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.malleable);
1484
1485
            // If a non-malleable satisfaction exists, it must be canonical.
1486
4.82k
            if (ret.sat.available != Availability::NO && !ret.sat.malleable) CHECK_NONFATAL(!ret.sat.non_canon);
1487
1488
4.82k
            return ret;
1489
4.82k
        };
1490
1491
4.82k
        return TreeEval<InputResult>(tester);
1492
4.82k
    }
miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const
Line
Count
Source
1247
4.32k
    internal::InputResult ProduceInput(const Ctx& ctx) const {
1248
4.32k
        using namespace internal;
1249
1250
        // Internal function which is invoked for every tree node, constructing satisfaction/dissatisfactions
1251
        // given those of its subnodes.
1252
4.32k
        auto helper = [&ctx](const Node& node, std::span<InputResult> subres) -> InputResult {
1253
4.32k
            switch (node.fragment) {
1254
4.32k
                case Fragment::PK_K: {
1255
4.32k
                    std::vector<unsigned char> sig;
1256
4.32k
                    Availability avail = ctx.Sign(node.keys[0], sig);
1257
4.32k
                    return {ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
1258
4.32k
                }
1259
4.32k
                case Fragment::PK_H: {
1260
4.32k
                    std::vector<unsigned char> key = ctx.ToPKBytes(node.keys[0]), sig;
1261
4.32k
                    Availability avail = ctx.Sign(node.keys[0], sig);
1262
4.32k
                    return {ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
1263
4.32k
                }
1264
4.32k
                case Fragment::MULTI_A: {
1265
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1266
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1267
4.32k
                    std::vector<InputStack> sats = Vector(EMPTY);
1268
4.32k
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1269
                        // Get the signature for the i'th key in reverse order (the signature for the first key needs to
1270
                        // be at the top of the stack, contrary to CHECKMULTISIG's satisfaction).
1271
4.32k
                        std::vector<unsigned char> sig;
1272
4.32k
                        Availability avail = ctx.Sign(node.keys[node.keys.size() - 1 - i], sig);
1273
                        // Compute signature stack for just this key.
1274
4.32k
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1275
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1276
                        // next_sats[j] are equal to either the existing sats[j] + ZERO, or sats[j-1] plus a signature
1277
                        // for the current (i'th) key. The very last element needs all signatures filled.
1278
4.32k
                        std::vector<InputStack> next_sats;
1279
4.32k
                        next_sats.push_back(sats[0] + ZERO);
1280
4.32k
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + ZERO) | (std::move(sats[j - 1]) + sat));
1281
4.32k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1282
                        // Switch over.
1283
4.32k
                        sats = std::move(next_sats);
1284
4.32k
                    }
1285
                    // The dissatisfaction consists of as many empty vectors as there are keys, which is the same as
1286
                    // satisfying 0 keys.
1287
4.32k
                    auto& nsat{sats[0]};
1288
4.32k
                    CHECK_NONFATAL(node.k != 0);
1289
4.32k
                    assert(node.k < sats.size());
1290
4.32k
                    return {std::move(nsat), std::move(sats[node.k])};
1291
4.32k
                }
1292
4.32k
                case Fragment::MULTI: {
1293
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1294
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1295
                    // sats[0] starts off being {0}, due to the CHECKMULTISIG bug that pops off one element too many.
1296
4.32k
                    std::vector<InputStack> sats = Vector(ZERO);
1297
4.32k
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1298
4.32k
                        std::vector<unsigned char> sig;
1299
4.32k
                        Availability avail = ctx.Sign(node.keys[i], sig);
1300
                        // Compute signature stack for just the i'th key.
1301
4.32k
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1302
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1303
                        // next_sats[j] are equal to either the existing sats[j], or sats[j-1] plus a signature for the
1304
                        // current (i'th) key. The very last element needs all signatures filled.
1305
4.32k
                        std::vector<InputStack> next_sats;
1306
4.32k
                        next_sats.push_back(sats[0]);
1307
4.32k
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
1308
4.32k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1309
                        // Switch over.
1310
4.32k
                        sats = std::move(next_sats);
1311
4.32k
                    }
1312
                    // The dissatisfaction consists of k+1 stack elements all equal to 0.
1313
4.32k
                    InputStack nsat = ZERO;
1314
4.32k
                    for (size_t i = 0; i < node.k; ++i) nsat = std::move(nsat) + ZERO;
1315
4.32k
                    assert(node.k < sats.size());
1316
4.32k
                    return {std::move(nsat), std::move(sats[node.k])};
1317
4.32k
                }
1318
4.32k
                case Fragment::THRESH: {
1319
                    // sats[k] represents the best stack that satisfies k out of the *last* i subexpressions.
1320
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1321
                    // sats[0] starts off empty.
1322
4.32k
                    std::vector<InputStack> sats = Vector(EMPTY);
1323
4.32k
                    for (size_t i = 0; i < subres.size(); ++i) {
1324
                        // Introduce an alias for the i'th last satisfaction/dissatisfaction.
1325
4.32k
                        auto& res = subres[subres.size() - i - 1];
1326
                        // Compute the next sats vector: next_sats[0] is sats[0] plus res.nsat (thus containing all dissatisfactions
1327
                        // so far. next_sats[j] is either sats[j] + res.nsat (reusing j earlier satisfactions) or sats[j-1] + res.sat
1328
                        // (reusing j-1 earlier satisfactions plus a new one). The very last next_sats[j] is all satisfactions.
1329
4.32k
                        std::vector<InputStack> next_sats;
1330
4.32k
                        next_sats.push_back(sats[0] + res.nsat);
1331
4.32k
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + res.nsat) | (std::move(sats[j - 1]) + res.sat));
1332
4.32k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
1333
                        // Switch over.
1334
4.32k
                        sats = std::move(next_sats);
1335
4.32k
                    }
1336
                    // At this point, sats[k].sat is the best satisfaction for the overall thresh() node. The best dissatisfaction
1337
                    // is computed by gathering all sats[i].nsat for i != k.
1338
4.32k
                    InputStack nsat = INVALID;
1339
4.32k
                    for (size_t i = 0; i < sats.size(); ++i) {
1340
                        // i==k is the satisfaction; i==0 is the canonical dissatisfaction;
1341
                        // the rest are non-canonical (a no-signature dissatisfaction - the i=0
1342
                        // form - is always available) and malleable (due to overcompleteness).
1343
                        // Marking the solutions malleable here is not strictly necessary, as they
1344
                        // should already never be picked in non-malleable solutions due to the
1345
                        // availability of the i=0 form.
1346
4.32k
                        if (i != 0 && i != node.k) sats[i].SetMalleable().SetNonCanon();
1347
                        // Include all dissatisfactions (even these non-canonical ones) in nsat.
1348
4.32k
                        if (i != node.k) nsat = std::move(nsat) | std::move(sats[i]);
1349
4.32k
                    }
1350
4.32k
                    assert(node.k < sats.size());
1351
4.32k
                    return {std::move(nsat), std::move(sats[node.k])};
1352
4.32k
                }
1353
4.32k
                case Fragment::OLDER: {
1354
4.32k
                    return {INVALID, ctx.CheckOlder(node.k) ? EMPTY : INVALID};
1355
4.32k
                }
1356
4.32k
                case Fragment::AFTER: {
1357
4.32k
                    return {INVALID, ctx.CheckAfter(node.k) ? EMPTY : INVALID};
1358
4.32k
                }
1359
4.32k
                case Fragment::SHA256: {
1360
4.32k
                    std::vector<unsigned char> preimage;
1361
4.32k
                    Availability avail = ctx.SatSHA256(node.data, preimage);
1362
4.32k
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1363
4.32k
                }
1364
4.32k
                case Fragment::RIPEMD160: {
1365
4.32k
                    std::vector<unsigned char> preimage;
1366
4.32k
                    Availability avail = ctx.SatRIPEMD160(node.data, preimage);
1367
4.32k
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1368
4.32k
                }
1369
4.32k
                case Fragment::HASH256: {
1370
4.32k
                    std::vector<unsigned char> preimage;
1371
4.32k
                    Availability avail = ctx.SatHASH256(node.data, preimage);
1372
4.32k
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1373
4.32k
                }
1374
4.32k
                case Fragment::HASH160: {
1375
4.32k
                    std::vector<unsigned char> preimage;
1376
4.32k
                    Availability avail = ctx.SatHASH160(node.data, preimage);
1377
4.32k
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1378
4.32k
                }
1379
4.32k
                case Fragment::AND_V: {
1380
4.32k
                    auto& x = subres[0], &y = subres[1];
1381
                    // As the dissatisfaction here only consist of a single option, it doesn't
1382
                    // actually need to be listed (it's not required for reasoning about malleability of
1383
                    // other options), and is never required (no valid miniscript relies on the ability
1384
                    // to satisfy the type V left subexpression). It's still listed here for
1385
                    // completeness, as a hypothetical (not currently implemented) satisfier that doesn't
1386
                    // care about malleability might in some cases prefer it still.
1387
4.32k
                    return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
1388
4.32k
                }
1389
4.32k
                case Fragment::AND_B: {
1390
4.32k
                    auto& x = subres[0], &y = subres[1];
1391
                    // Note that it is not strictly necessary to mark the 2nd and 3rd dissatisfaction here
1392
                    // as malleable. While they are definitely malleable, they are also non-canonical due
1393
                    // to the guaranteed existence of a no-signature other dissatisfaction (the 1st)
1394
                    // option. Because of that, the 2nd and 3rd option will never be chosen, even if they
1395
                    // weren't marked as malleable.
1396
4.32k
                    return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
1397
4.32k
                }
1398
4.32k
                case Fragment::OR_B: {
1399
4.32k
                    auto& x = subres[0], &z = subres[1];
1400
                    // The (sat(Z) sat(X)) solution is overcomplete (attacker can change either into dsat).
1401
4.32k
                    return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
1402
4.32k
                }
1403
4.32k
                case Fragment::OR_C: {
1404
4.32k
                    auto& x = subres[0], &z = subres[1];
1405
4.32k
                    return {INVALID, std::move(x.sat) | (z.sat + x.nsat)};
1406
4.32k
                }
1407
4.32k
                case Fragment::OR_D: {
1408
4.32k
                    auto& x = subres[0], &z = subres[1];
1409
4.32k
                    return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
1410
4.32k
                }
1411
4.32k
                case Fragment::OR_I: {
1412
4.32k
                    auto& x = subres[0], &z = subres[1];
1413
4.32k
                    return {(x.nsat + ONE) | (z.nsat + ZERO), (x.sat + ONE) | (z.sat + ZERO)};
1414
4.32k
                }
1415
4.32k
                case Fragment::ANDOR: {
1416
4.32k
                    auto& x = subres[0], &y = subres[1], &z = subres[2];
1417
4.32k
                    return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
1418
4.32k
                }
1419
4.32k
                case Fragment::WRAP_A:
1420
4.32k
                case Fragment::WRAP_S:
1421
4.32k
                case Fragment::WRAP_C:
1422
4.32k
                case Fragment::WRAP_N:
1423
4.32k
                    return std::move(subres[0]);
1424
4.32k
                case Fragment::WRAP_D: {
1425
4.32k
                    auto &x = subres[0];
1426
4.32k
                    return {ZERO, x.sat + ONE};
1427
4.32k
                }
1428
4.32k
                case Fragment::WRAP_J: {
1429
4.32k
                    auto &x = subres[0];
1430
                    // If a dissatisfaction with a nonzero top stack element exists, an alternative dissatisfaction exists.
1431
                    // As the dissatisfaction logic currently doesn't keep track of this nonzeroness property, and thus even
1432
                    // if a dissatisfaction with a top zero element is found, we don't know whether another one with a
1433
                    // nonzero top stack element exists. Make the conservative assumption that whenever the subexpression is weakly
1434
                    // dissatisfiable, this alternative dissatisfaction exists and leads to malleability.
1435
4.32k
                    return {InputStack(ZERO).SetMalleable(x.nsat.available != Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
1436
4.32k
                }
1437
4.32k
                case Fragment::WRAP_V: {
1438
4.32k
                    auto &x = subres[0];
1439
4.32k
                    return {INVALID, std::move(x.sat)};
1440
4.32k
                }
1441
4.32k
                case Fragment::JUST_0: return {EMPTY, INVALID};
1442
4.32k
                case Fragment::JUST_1: return {INVALID, EMPTY};
1443
4.32k
            }
1444
4.32k
            assert(false);
1445
4.32k
            return {INVALID, INVALID};
1446
4.32k
        };
1447
1448
4.32k
        auto tester = [&helper](const Node& node, std::span<InputResult> subres) -> InputResult {
1449
4.32k
            auto ret = helper(node, subres);
1450
1451
            // Do a consistency check between the satisfaction code and the type checker
1452
            // (the actual satisfaction code in ProduceInputHelper does not use GetType)
1453
1454
            // For 'z' nodes, available satisfactions/dissatisfactions must have stack size 0.
1455
4.32k
            if (node.GetType() << "z"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 0);
1456
4.32k
            if (node.GetType() << "z"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 0);
1457
1458
            // For 'o' nodes, available satisfactions/dissatisfactions must have stack size 1.
1459
4.32k
            if (node.GetType() << "o"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 1);
1460
4.32k
            if (node.GetType() << "o"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 1);
1461
1462
            // For 'n' nodes, available satisfactions/dissatisfactions must have stack size 1 or larger. For satisfactions,
1463
            // the top element cannot be 0.
1464
4.32k
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() >= 1);
1465
4.32k
            if (node.GetType() << "n"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() >= 1);
1466
4.32k
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.stack.back().empty());
1467
1468
            // For 'd' nodes, a dissatisfaction must exist, and they must not need a signature. If it is non-malleable,
1469
            // it must be canonical.
1470
4.32k
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1471
4.32k
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(!ret.nsat.has_sig);
1472
4.32k
            if (node.GetType() << "d"_mst && !ret.nsat.malleable) CHECK_NONFATAL(!ret.nsat.non_canon);
1473
1474
            // For 'f'/'s' nodes, dissatisfactions/satisfactions must have a signature.
1475
4.32k
            if (node.GetType() << "f"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.has_sig);
1476
4.32k
            if (node.GetType() << "s"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.has_sig);
1477
1478
            // For non-malleable 'e' nodes, a non-malleable dissatisfaction must exist.
1479
4.32k
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1480
4.32k
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(!ret.nsat.malleable);
1481
1482
            // For 'm' nodes, if a satisfaction exists, it must be non-malleable.
1483
4.32k
            if (node.GetType() << "m"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.malleable);
1484
1485
            // If a non-malleable satisfaction exists, it must be canonical.
1486
4.32k
            if (ret.sat.available != Availability::NO && !ret.sat.malleable) CHECK_NONFATAL(!ret.sat.non_canon);
1487
1488
4.32k
            return ret;
1489
4.32k
        };
1490
1491
4.32k
        return TreeEval<InputResult>(tester);
1492
4.32k
    }
miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const
Line
Count
Source
1247
215
    internal::InputResult ProduceInput(const Ctx& ctx) const {
1248
215
        using namespace internal;
1249
1250
        // Internal function which is invoked for every tree node, constructing satisfaction/dissatisfactions
1251
        // given those of its subnodes.
1252
215
        auto helper = [&ctx](const Node& node, std::span<InputResult> subres) -> InputResult {
1253
215
            switch (node.fragment) {
1254
215
                case Fragment::PK_K: {
1255
215
                    std::vector<unsigned char> sig;
1256
215
                    Availability avail = ctx.Sign(node.keys[0], sig);
1257
215
                    return {ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
1258
215
                }
1259
215
                case Fragment::PK_H: {
1260
215
                    std::vector<unsigned char> key = ctx.ToPKBytes(node.keys[0]), sig;
1261
215
                    Availability avail = ctx.Sign(node.keys[0], sig);
1262
215
                    return {ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
1263
215
                }
1264
215
                case Fragment::MULTI_A: {
1265
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1266
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1267
215
                    std::vector<InputStack> sats = Vector(EMPTY);
1268
215
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1269
                        // Get the signature for the i'th key in reverse order (the signature for the first key needs to
1270
                        // be at the top of the stack, contrary to CHECKMULTISIG's satisfaction).
1271
215
                        std::vector<unsigned char> sig;
1272
215
                        Availability avail = ctx.Sign(node.keys[node.keys.size() - 1 - i], sig);
1273
                        // Compute signature stack for just this key.
1274
215
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1275
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1276
                        // next_sats[j] are equal to either the existing sats[j] + ZERO, or sats[j-1] plus a signature
1277
                        // for the current (i'th) key. The very last element needs all signatures filled.
1278
215
                        std::vector<InputStack> next_sats;
1279
215
                        next_sats.push_back(sats[0] + ZERO);
1280
215
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + ZERO) | (std::move(sats[j - 1]) + sat));
1281
215
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1282
                        // Switch over.
1283
215
                        sats = std::move(next_sats);
1284
215
                    }
1285
                    // The dissatisfaction consists of as many empty vectors as there are keys, which is the same as
1286
                    // satisfying 0 keys.
1287
215
                    auto& nsat{sats[0]};
1288
215
                    CHECK_NONFATAL(node.k != 0);
1289
215
                    assert(node.k < sats.size());
1290
215
                    return {std::move(nsat), std::move(sats[node.k])};
1291
215
                }
1292
215
                case Fragment::MULTI: {
1293
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1294
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1295
                    // sats[0] starts off being {0}, due to the CHECKMULTISIG bug that pops off one element too many.
1296
215
                    std::vector<InputStack> sats = Vector(ZERO);
1297
215
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1298
215
                        std::vector<unsigned char> sig;
1299
215
                        Availability avail = ctx.Sign(node.keys[i], sig);
1300
                        // Compute signature stack for just the i'th key.
1301
215
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1302
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1303
                        // next_sats[j] are equal to either the existing sats[j], or sats[j-1] plus a signature for the
1304
                        // current (i'th) key. The very last element needs all signatures filled.
1305
215
                        std::vector<InputStack> next_sats;
1306
215
                        next_sats.push_back(sats[0]);
1307
215
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
1308
215
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1309
                        // Switch over.
1310
215
                        sats = std::move(next_sats);
1311
215
                    }
1312
                    // The dissatisfaction consists of k+1 stack elements all equal to 0.
1313
215
                    InputStack nsat = ZERO;
1314
215
                    for (size_t i = 0; i < node.k; ++i) nsat = std::move(nsat) + ZERO;
1315
215
                    assert(node.k < sats.size());
1316
215
                    return {std::move(nsat), std::move(sats[node.k])};
1317
215
                }
1318
215
                case Fragment::THRESH: {
1319
                    // sats[k] represents the best stack that satisfies k out of the *last* i subexpressions.
1320
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1321
                    // sats[0] starts off empty.
1322
215
                    std::vector<InputStack> sats = Vector(EMPTY);
1323
215
                    for (size_t i = 0; i < subres.size(); ++i) {
1324
                        // Introduce an alias for the i'th last satisfaction/dissatisfaction.
1325
215
                        auto& res = subres[subres.size() - i - 1];
1326
                        // Compute the next sats vector: next_sats[0] is sats[0] plus res.nsat (thus containing all dissatisfactions
1327
                        // so far. next_sats[j] is either sats[j] + res.nsat (reusing j earlier satisfactions) or sats[j-1] + res.sat
1328
                        // (reusing j-1 earlier satisfactions plus a new one). The very last next_sats[j] is all satisfactions.
1329
215
                        std::vector<InputStack> next_sats;
1330
215
                        next_sats.push_back(sats[0] + res.nsat);
1331
215
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + res.nsat) | (std::move(sats[j - 1]) + res.sat));
1332
215
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
1333
                        // Switch over.
1334
215
                        sats = std::move(next_sats);
1335
215
                    }
1336
                    // At this point, sats[k].sat is the best satisfaction for the overall thresh() node. The best dissatisfaction
1337
                    // is computed by gathering all sats[i].nsat for i != k.
1338
215
                    InputStack nsat = INVALID;
1339
215
                    for (size_t i = 0; i < sats.size(); ++i) {
1340
                        // i==k is the satisfaction; i==0 is the canonical dissatisfaction;
1341
                        // the rest are non-canonical (a no-signature dissatisfaction - the i=0
1342
                        // form - is always available) and malleable (due to overcompleteness).
1343
                        // Marking the solutions malleable here is not strictly necessary, as they
1344
                        // should already never be picked in non-malleable solutions due to the
1345
                        // availability of the i=0 form.
1346
215
                        if (i != 0 && i != node.k) sats[i].SetMalleable().SetNonCanon();
1347
                        // Include all dissatisfactions (even these non-canonical ones) in nsat.
1348
215
                        if (i != node.k) nsat = std::move(nsat) | std::move(sats[i]);
1349
215
                    }
1350
215
                    assert(node.k < sats.size());
1351
215
                    return {std::move(nsat), std::move(sats[node.k])};
1352
215
                }
1353
215
                case Fragment::OLDER: {
1354
215
                    return {INVALID, ctx.CheckOlder(node.k) ? EMPTY : INVALID};
1355
215
                }
1356
215
                case Fragment::AFTER: {
1357
215
                    return {INVALID, ctx.CheckAfter(node.k) ? EMPTY : INVALID};
1358
215
                }
1359
215
                case Fragment::SHA256: {
1360
215
                    std::vector<unsigned char> preimage;
1361
215
                    Availability avail = ctx.SatSHA256(node.data, preimage);
1362
215
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1363
215
                }
1364
215
                case Fragment::RIPEMD160: {
1365
215
                    std::vector<unsigned char> preimage;
1366
215
                    Availability avail = ctx.SatRIPEMD160(node.data, preimage);
1367
215
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1368
215
                }
1369
215
                case Fragment::HASH256: {
1370
215
                    std::vector<unsigned char> preimage;
1371
215
                    Availability avail = ctx.SatHASH256(node.data, preimage);
1372
215
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1373
215
                }
1374
215
                case Fragment::HASH160: {
1375
215
                    std::vector<unsigned char> preimage;
1376
215
                    Availability avail = ctx.SatHASH160(node.data, preimage);
1377
215
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1378
215
                }
1379
215
                case Fragment::AND_V: {
1380
215
                    auto& x = subres[0], &y = subres[1];
1381
                    // As the dissatisfaction here only consist of a single option, it doesn't
1382
                    // actually need to be listed (it's not required for reasoning about malleability of
1383
                    // other options), and is never required (no valid miniscript relies on the ability
1384
                    // to satisfy the type V left subexpression). It's still listed here for
1385
                    // completeness, as a hypothetical (not currently implemented) satisfier that doesn't
1386
                    // care about malleability might in some cases prefer it still.
1387
215
                    return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
1388
215
                }
1389
215
                case Fragment::AND_B: {
1390
215
                    auto& x = subres[0], &y = subres[1];
1391
                    // Note that it is not strictly necessary to mark the 2nd and 3rd dissatisfaction here
1392
                    // as malleable. While they are definitely malleable, they are also non-canonical due
1393
                    // to the guaranteed existence of a no-signature other dissatisfaction (the 1st)
1394
                    // option. Because of that, the 2nd and 3rd option will never be chosen, even if they
1395
                    // weren't marked as malleable.
1396
215
                    return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
1397
215
                }
1398
215
                case Fragment::OR_B: {
1399
215
                    auto& x = subres[0], &z = subres[1];
1400
                    // The (sat(Z) sat(X)) solution is overcomplete (attacker can change either into dsat).
1401
215
                    return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
1402
215
                }
1403
215
                case Fragment::OR_C: {
1404
215
                    auto& x = subres[0], &z = subres[1];
1405
215
                    return {INVALID, std::move(x.sat) | (z.sat + x.nsat)};
1406
215
                }
1407
215
                case Fragment::OR_D: {
1408
215
                    auto& x = subres[0], &z = subres[1];
1409
215
                    return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
1410
215
                }
1411
215
                case Fragment::OR_I: {
1412
215
                    auto& x = subres[0], &z = subres[1];
1413
215
                    return {(x.nsat + ONE) | (z.nsat + ZERO), (x.sat + ONE) | (z.sat + ZERO)};
1414
215
                }
1415
215
                case Fragment::ANDOR: {
1416
215
                    auto& x = subres[0], &y = subres[1], &z = subres[2];
1417
215
                    return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
1418
215
                }
1419
215
                case Fragment::WRAP_A:
1420
215
                case Fragment::WRAP_S:
1421
215
                case Fragment::WRAP_C:
1422
215
                case Fragment::WRAP_N:
1423
215
                    return std::move(subres[0]);
1424
215
                case Fragment::WRAP_D: {
1425
215
                    auto &x = subres[0];
1426
215
                    return {ZERO, x.sat + ONE};
1427
215
                }
1428
215
                case Fragment::WRAP_J: {
1429
215
                    auto &x = subres[0];
1430
                    // If a dissatisfaction with a nonzero top stack element exists, an alternative dissatisfaction exists.
1431
                    // As the dissatisfaction logic currently doesn't keep track of this nonzeroness property, and thus even
1432
                    // if a dissatisfaction with a top zero element is found, we don't know whether another one with a
1433
                    // nonzero top stack element exists. Make the conservative assumption that whenever the subexpression is weakly
1434
                    // dissatisfiable, this alternative dissatisfaction exists and leads to malleability.
1435
215
                    return {InputStack(ZERO).SetMalleable(x.nsat.available != Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
1436
215
                }
1437
215
                case Fragment::WRAP_V: {
1438
215
                    auto &x = subres[0];
1439
215
                    return {INVALID, std::move(x.sat)};
1440
215
                }
1441
215
                case Fragment::JUST_0: return {EMPTY, INVALID};
1442
215
                case Fragment::JUST_1: return {INVALID, EMPTY};
1443
215
            }
1444
215
            assert(false);
1445
215
            return {INVALID, INVALID};
1446
215
        };
1447
1448
215
        auto tester = [&helper](const Node& node, std::span<InputResult> subres) -> InputResult {
1449
215
            auto ret = helper(node, subres);
1450
1451
            // Do a consistency check between the satisfaction code and the type checker
1452
            // (the actual satisfaction code in ProduceInputHelper does not use GetType)
1453
1454
            // For 'z' nodes, available satisfactions/dissatisfactions must have stack size 0.
1455
215
            if (node.GetType() << "z"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 0);
1456
215
            if (node.GetType() << "z"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 0);
1457
1458
            // For 'o' nodes, available satisfactions/dissatisfactions must have stack size 1.
1459
215
            if (node.GetType() << "o"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 1);
1460
215
            if (node.GetType() << "o"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 1);
1461
1462
            // For 'n' nodes, available satisfactions/dissatisfactions must have stack size 1 or larger. For satisfactions,
1463
            // the top element cannot be 0.
1464
215
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() >= 1);
1465
215
            if (node.GetType() << "n"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() >= 1);
1466
215
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.stack.back().empty());
1467
1468
            // For 'd' nodes, a dissatisfaction must exist, and they must not need a signature. If it is non-malleable,
1469
            // it must be canonical.
1470
215
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1471
215
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(!ret.nsat.has_sig);
1472
215
            if (node.GetType() << "d"_mst && !ret.nsat.malleable) CHECK_NONFATAL(!ret.nsat.non_canon);
1473
1474
            // For 'f'/'s' nodes, dissatisfactions/satisfactions must have a signature.
1475
215
            if (node.GetType() << "f"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.has_sig);
1476
215
            if (node.GetType() << "s"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.has_sig);
1477
1478
            // For non-malleable 'e' nodes, a non-malleable dissatisfaction must exist.
1479
215
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1480
215
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(!ret.nsat.malleable);
1481
1482
            // For 'm' nodes, if a satisfaction exists, it must be non-malleable.
1483
215
            if (node.GetType() << "m"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.malleable);
1484
1485
            // If a non-malleable satisfaction exists, it must be canonical.
1486
215
            if (ret.sat.available != Availability::NO && !ret.sat.malleable) CHECK_NONFATAL(!ret.sat.non_canon);
1487
1488
215
            return ret;
1489
215
        };
1490
1491
215
        return TreeEval<InputResult>(tester);
1492
215
    }
1493
1494
public:
1495
    /** Update duplicate key information in this Node.
1496
     *
1497
     * This uses a custom key comparator provided by the context in order to still detect duplicates
1498
     * for more complicated types.
1499
     */
1500
    template<typename Ctx> void DuplicateKeyCheck(const Ctx& ctx) const
1501
5.64k
    {
1502
        // We cannot use a lambda here, as lambdas are non assignable, and the set operations
1503
        // below require moving the comparators around.
1504
5.64k
        struct Comp {
1505
5.64k
            const Ctx* ctx_ptr;
1506
3.00M
            Comp(const Ctx& ctx) : ctx_ptr(&ctx) {}
miniscript_tests.cpp:void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp::Comp((anonymous namespace)::KeyConverter const&)
Line
Count
Source
1506
23.2k
            Comp(const Ctx& ctx) : ctx_ptr(&ctx) {}
descriptor.cpp:void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp::Comp((anonymous namespace)::KeyParser const&)
Line
Count
Source
1506
995k
            Comp(const Ctx& ctx) : ctx_ptr(&ctx) {}
void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp::Comp(TapSatisfier const&)
Line
Count
Source
1506
1.98M
            Comp(const Ctx& ctx) : ctx_ptr(&ctx) {}
void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp::Comp(WshSatisfier const&)
Line
Count
Source
1506
3.13k
            Comp(const Ctx& ctx) : ctx_ptr(&ctx) {}
1507
293k
            bool operator()(const Key& a, const Key& b) const { return ctx_ptr->KeyCompare(a, b); }
miniscript_tests.cpp:void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp::operator()(CPubKey const&, CPubKey const&) const
Line
Count
Source
1507
6.98k
            bool operator()(const Key& a, const Key& b) const { return ctx_ptr->KeyCompare(a, b); }
descriptor.cpp:void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp::operator()(unsigned int const&, unsigned int const&) const
Line
Count
Source
1507
4.23k
            bool operator()(const Key& a, const Key& b) const { return ctx_ptr->KeyCompare(a, b); }
void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp::operator()(XOnlyPubKey const&, XOnlyPubKey const&) const
Line
Count
Source
1507
280k
            bool operator()(const Key& a, const Key& b) const { return ctx_ptr->KeyCompare(a, b); }
void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp::operator()(CPubKey const&, CPubKey const&) const
Line
Count
Source
1507
1.26k
            bool operator()(const Key& a, const Key& b) const { return ctx_ptr->KeyCompare(a, b); }
1508
5.64k
        };
1509
1510
        // state in the recursive computation:
1511
        // - std::nullopt means "this node has duplicates"
1512
        // - an std::set means "this node has no duplicate keys, and they are: ...".
1513
5.64k
        using keyset = std::set<Key, Comp>;
1514
5.64k
        using state = std::optional<keyset>;
1515
1516
3.00M
        auto upfn = [&ctx](const Node& node, std::span<state> subs) -> state {
1517
            // If this node is already known to have duplicates, nothing left to do.
1518
3.00M
            if (node.has_duplicate_keys.has_value() && *node.has_duplicate_keys) return {};
1519
1520
            // Check if one of the children is already known to have duplicates.
1521
3.00M
            for (auto& sub : subs) {
1522
3.00M
                if (!sub.has_value()) {
1523
0
                    node.has_duplicate_keys = true;
1524
0
                    return {};
1525
0
                }
1526
3.00M
            }
1527
1528
            // Start building the set of keys involved in this node and children.
1529
            // Start by keys in this node directly.
1530
3.00M
            size_t keys_count = node.keys.size();
1531
3.00M
            keyset key_set{node.keys.begin(), node.keys.end(), Comp(ctx)};
1532
3.00M
            if (key_set.size() != keys_count) {
1533
                // It already has duplicates; bail out.
1534
88
                node.has_duplicate_keys = true;
1535
88
                return {};
1536
88
            }
1537
1538
            // Merge the keys from the children into this set.
1539
3.00M
            for (auto& sub : subs) {
1540
3.00M
                keys_count += sub->size();
1541
                // Small optimization: std::set::merge is linear in the size of the second arg but
1542
                // logarithmic in the size of the first.
1543
3.00M
                if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1544
3.00M
                key_set.merge(*sub);
1545
3.00M
                if (key_set.size() != keys_count) {
1546
8
                    node.has_duplicate_keys = true;
1547
8
                    return {};
1548
8
                }
1549
3.00M
            }
1550
1551
3.00M
            node.has_duplicate_keys = false;
1552
3.00M
            return key_set;
1553
3.00M
        };
miniscript_tests.cpp:void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)::operator()(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>) const
Line
Count
Source
1516
23.2k
        auto upfn = [&ctx](const Node& node, std::span<state> subs) -> state {
1517
            // If this node is already known to have duplicates, nothing left to do.
1518
23.2k
            if (node.has_duplicate_keys.has_value() && *node.has_duplicate_keys) return {};
1519
1520
            // Check if one of the children is already known to have duplicates.
1521
23.2k
            for (auto& sub : subs) {
1522
22.9k
                if (!sub.has_value()) {
1523
0
                    node.has_duplicate_keys = true;
1524
0
                    return {};
1525
0
                }
1526
22.9k
            }
1527
1528
            // Start building the set of keys involved in this node and children.
1529
            // Start by keys in this node directly.
1530
23.2k
            size_t keys_count = node.keys.size();
1531
23.2k
            keyset key_set{node.keys.begin(), node.keys.end(), Comp(ctx)};
1532
23.2k
            if (key_set.size() != keys_count) {
1533
                // It already has duplicates; bail out.
1534
0
                node.has_duplicate_keys = true;
1535
0
                return {};
1536
0
            }
1537
1538
            // Merge the keys from the children into this set.
1539
23.2k
            for (auto& sub : subs) {
1540
22.9k
                keys_count += sub->size();
1541
                // Small optimization: std::set::merge is linear in the size of the second arg but
1542
                // logarithmic in the size of the first.
1543
22.9k
                if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1544
22.9k
                key_set.merge(*sub);
1545
22.9k
                if (key_set.size() != keys_count) {
1546
6
                    node.has_duplicate_keys = true;
1547
6
                    return {};
1548
6
                }
1549
22.9k
            }
1550
1551
23.2k
            node.has_duplicate_keys = false;
1552
23.2k
            return key_set;
1553
23.2k
        };
descriptor.cpp:void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::'lambda'(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>)::operator()(miniscript::Node<unsigned int> const&, std::span<std::optional<std::set<unsigned int, void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const::Comp, std::allocator<unsigned int>>>, 18446744073709551615ul>) const
Line
Count
Source
1516
995k
        auto upfn = [&ctx](const Node& node, std::span<state> subs) -> state {
1517
            // If this node is already known to have duplicates, nothing left to do.
1518
995k
            if (node.has_duplicate_keys.has_value() && *node.has_duplicate_keys) return {};
1519
1520
            // Check if one of the children is already known to have duplicates.
1521
995k
            for (auto& sub : subs) {
1522
994k
                if (!sub.has_value()) {
1523
0
                    node.has_duplicate_keys = true;
1524
0
                    return {};
1525
0
                }
1526
994k
            }
1527
1528
            // Start building the set of keys involved in this node and children.
1529
            // Start by keys in this node directly.
1530
995k
            size_t keys_count = node.keys.size();
1531
995k
            keyset key_set{node.keys.begin(), node.keys.end(), Comp(ctx)};
1532
995k
            if (key_set.size() != keys_count) {
1533
                // It already has duplicates; bail out.
1534
0
                node.has_duplicate_keys = true;
1535
0
                return {};
1536
0
            }
1537
1538
            // Merge the keys from the children into this set.
1539
995k
            for (auto& sub : subs) {
1540
994k
                keys_count += sub->size();
1541
                // Small optimization: std::set::merge is linear in the size of the second arg but
1542
                // logarithmic in the size of the first.
1543
994k
                if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1544
994k
                key_set.merge(*sub);
1545
994k
                if (key_set.size() != keys_count) {
1546
2
                    node.has_duplicate_keys = true;
1547
2
                    return {};
1548
2
                }
1549
994k
            }
1550
1551
995k
            node.has_duplicate_keys = false;
1552
995k
            return key_set;
1553
995k
        };
void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::'lambda'(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>)::operator()(miniscript::Node<XOnlyPubKey> const&, std::span<std::optional<std::set<XOnlyPubKey, void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp, std::allocator<XOnlyPubKey>>>, 18446744073709551615ul>) const
Line
Count
Source
1516
1.98M
        auto upfn = [&ctx](const Node& node, std::span<state> subs) -> state {
1517
            // If this node is already known to have duplicates, nothing left to do.
1518
1.98M
            if (node.has_duplicate_keys.has_value() && *node.has_duplicate_keys) return {};
1519
1520
            // Check if one of the children is already known to have duplicates.
1521
1.98M
            for (auto& sub : subs) {
1522
1.98M
                if (!sub.has_value()) {
1523
0
                    node.has_duplicate_keys = true;
1524
0
                    return {};
1525
0
                }
1526
1.98M
            }
1527
1528
            // Start building the set of keys involved in this node and children.
1529
            // Start by keys in this node directly.
1530
1.98M
            size_t keys_count = node.keys.size();
1531
1.98M
            keyset key_set{node.keys.begin(), node.keys.end(), Comp(ctx)};
1532
1.98M
            if (key_set.size() != keys_count) {
1533
                // It already has duplicates; bail out.
1534
88
                node.has_duplicate_keys = true;
1535
88
                return {};
1536
88
            }
1537
1538
            // Merge the keys from the children into this set.
1539
1.98M
            for (auto& sub : subs) {
1540
1.98M
                keys_count += sub->size();
1541
                // Small optimization: std::set::merge is linear in the size of the second arg but
1542
                // logarithmic in the size of the first.
1543
1.98M
                if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1544
1.98M
                key_set.merge(*sub);
1545
1.98M
                if (key_set.size() != keys_count) {
1546
0
                    node.has_duplicate_keys = true;
1547
0
                    return {};
1548
0
                }
1549
1.98M
            }
1550
1551
1.98M
            node.has_duplicate_keys = false;
1552
1.98M
            return key_set;
1553
1.98M
        };
void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::'lambda'(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>)::operator()(miniscript::Node<CPubKey> const&, std::span<std::optional<std::set<CPubKey, void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp, std::allocator<CPubKey>>>, 18446744073709551615ul>) const
Line
Count
Source
1516
3.13k
        auto upfn = [&ctx](const Node& node, std::span<state> subs) -> state {
1517
            // If this node is already known to have duplicates, nothing left to do.
1518
3.13k
            if (node.has_duplicate_keys.has_value() && *node.has_duplicate_keys) return {};
1519
1520
            // Check if one of the children is already known to have duplicates.
1521
3.13k
            for (auto& sub : subs) {
1522
2.91k
                if (!sub.has_value()) {
1523
0
                    node.has_duplicate_keys = true;
1524
0
                    return {};
1525
0
                }
1526
2.91k
            }
1527
1528
            // Start building the set of keys involved in this node and children.
1529
            // Start by keys in this node directly.
1530
3.13k
            size_t keys_count = node.keys.size();
1531
3.13k
            keyset key_set{node.keys.begin(), node.keys.end(), Comp(ctx)};
1532
3.13k
            if (key_set.size() != keys_count) {
1533
                // It already has duplicates; bail out.
1534
0
                node.has_duplicate_keys = true;
1535
0
                return {};
1536
0
            }
1537
1538
            // Merge the keys from the children into this set.
1539
3.13k
            for (auto& sub : subs) {
1540
2.91k
                keys_count += sub->size();
1541
                // Small optimization: std::set::merge is linear in the size of the second arg but
1542
                // logarithmic in the size of the first.
1543
2.91k
                if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1544
2.91k
                key_set.merge(*sub);
1545
2.91k
                if (key_set.size() != keys_count) {
1546
0
                    node.has_duplicate_keys = true;
1547
0
                    return {};
1548
0
                }
1549
2.91k
            }
1550
1551
3.13k
            node.has_duplicate_keys = false;
1552
3.13k
            return key_set;
1553
3.13k
        };
1554
1555
5.64k
        TreeEval<state>(upfn);
1556
5.64k
    }
miniscript_tests.cpp:void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const
Line
Count
Source
1501
313
    {
1502
        // We cannot use a lambda here, as lambdas are non assignable, and the set operations
1503
        // below require moving the comparators around.
1504
313
        struct Comp {
1505
313
            const Ctx* ctx_ptr;
1506
313
            Comp(const Ctx& ctx) : ctx_ptr(&ctx) {}
1507
313
            bool operator()(const Key& a, const Key& b) const { return ctx_ptr->KeyCompare(a, b); }
1508
313
        };
1509
1510
        // state in the recursive computation:
1511
        // - std::nullopt means "this node has duplicates"
1512
        // - an std::set means "this node has no duplicate keys, and they are: ...".
1513
313
        using keyset = std::set<Key, Comp>;
1514
313
        using state = std::optional<keyset>;
1515
1516
313
        auto upfn = [&ctx](const Node& node, std::span<state> subs) -> state {
1517
            // If this node is already known to have duplicates, nothing left to do.
1518
313
            if (node.has_duplicate_keys.has_value() && *node.has_duplicate_keys) return {};
1519
1520
            // Check if one of the children is already known to have duplicates.
1521
313
            for (auto& sub : subs) {
1522
313
                if (!sub.has_value()) {
1523
313
                    node.has_duplicate_keys = true;
1524
313
                    return {};
1525
313
                }
1526
313
            }
1527
1528
            // Start building the set of keys involved in this node and children.
1529
            // Start by keys in this node directly.
1530
313
            size_t keys_count = node.keys.size();
1531
313
            keyset key_set{node.keys.begin(), node.keys.end(), Comp(ctx)};
1532
313
            if (key_set.size() != keys_count) {
1533
                // It already has duplicates; bail out.
1534
313
                node.has_duplicate_keys = true;
1535
313
                return {};
1536
313
            }
1537
1538
            // Merge the keys from the children into this set.
1539
313
            for (auto& sub : subs) {
1540
313
                keys_count += sub->size();
1541
                // Small optimization: std::set::merge is linear in the size of the second arg but
1542
                // logarithmic in the size of the first.
1543
313
                if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1544
313
                key_set.merge(*sub);
1545
313
                if (key_set.size() != keys_count) {
1546
313
                    node.has_duplicate_keys = true;
1547
313
                    return {};
1548
313
                }
1549
313
            }
1550
1551
313
            node.has_duplicate_keys = false;
1552
313
            return key_set;
1553
313
        };
1554
1555
313
        TreeEval<state>(upfn);
1556
313
    }
descriptor.cpp:void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const
Line
Count
Source
1501
788
    {
1502
        // We cannot use a lambda here, as lambdas are non assignable, and the set operations
1503
        // below require moving the comparators around.
1504
788
        struct Comp {
1505
788
            const Ctx* ctx_ptr;
1506
788
            Comp(const Ctx& ctx) : ctx_ptr(&ctx) {}
1507
788
            bool operator()(const Key& a, const Key& b) const { return ctx_ptr->KeyCompare(a, b); }
1508
788
        };
1509
1510
        // state in the recursive computation:
1511
        // - std::nullopt means "this node has duplicates"
1512
        // - an std::set means "this node has no duplicate keys, and they are: ...".
1513
788
        using keyset = std::set<Key, Comp>;
1514
788
        using state = std::optional<keyset>;
1515
1516
788
        auto upfn = [&ctx](const Node& node, std::span<state> subs) -> state {
1517
            // If this node is already known to have duplicates, nothing left to do.
1518
788
            if (node.has_duplicate_keys.has_value() && *node.has_duplicate_keys) return {};
1519
1520
            // Check if one of the children is already known to have duplicates.
1521
788
            for (auto& sub : subs) {
1522
788
                if (!sub.has_value()) {
1523
788
                    node.has_duplicate_keys = true;
1524
788
                    return {};
1525
788
                }
1526
788
            }
1527
1528
            // Start building the set of keys involved in this node and children.
1529
            // Start by keys in this node directly.
1530
788
            size_t keys_count = node.keys.size();
1531
788
            keyset key_set{node.keys.begin(), node.keys.end(), Comp(ctx)};
1532
788
            if (key_set.size() != keys_count) {
1533
                // It already has duplicates; bail out.
1534
788
                node.has_duplicate_keys = true;
1535
788
                return {};
1536
788
            }
1537
1538
            // Merge the keys from the children into this set.
1539
788
            for (auto& sub : subs) {
1540
788
                keys_count += sub->size();
1541
                // Small optimization: std::set::merge is linear in the size of the second arg but
1542
                // logarithmic in the size of the first.
1543
788
                if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1544
788
                key_set.merge(*sub);
1545
788
                if (key_set.size() != keys_count) {
1546
788
                    node.has_duplicate_keys = true;
1547
788
                    return {};
1548
788
                }
1549
788
            }
1550
1551
788
            node.has_duplicate_keys = false;
1552
788
            return key_set;
1553
788
        };
1554
1555
788
        TreeEval<state>(upfn);
1556
788
    }
void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const
Line
Count
Source
1501
4.32k
    {
1502
        // We cannot use a lambda here, as lambdas are non assignable, and the set operations
1503
        // below require moving the comparators around.
1504
4.32k
        struct Comp {
1505
4.32k
            const Ctx* ctx_ptr;
1506
4.32k
            Comp(const Ctx& ctx) : ctx_ptr(&ctx) {}
1507
4.32k
            bool operator()(const Key& a, const Key& b) const { return ctx_ptr->KeyCompare(a, b); }
1508
4.32k
        };
1509
1510
        // state in the recursive computation:
1511
        // - std::nullopt means "this node has duplicates"
1512
        // - an std::set means "this node has no duplicate keys, and they are: ...".
1513
4.32k
        using keyset = std::set<Key, Comp>;
1514
4.32k
        using state = std::optional<keyset>;
1515
1516
4.32k
        auto upfn = [&ctx](const Node& node, std::span<state> subs) -> state {
1517
            // If this node is already known to have duplicates, nothing left to do.
1518
4.32k
            if (node.has_duplicate_keys.has_value() && *node.has_duplicate_keys) return {};
1519
1520
            // Check if one of the children is already known to have duplicates.
1521
4.32k
            for (auto& sub : subs) {
1522
4.32k
                if (!sub.has_value()) {
1523
4.32k
                    node.has_duplicate_keys = true;
1524
4.32k
                    return {};
1525
4.32k
                }
1526
4.32k
            }
1527
1528
            // Start building the set of keys involved in this node and children.
1529
            // Start by keys in this node directly.
1530
4.32k
            size_t keys_count = node.keys.size();
1531
4.32k
            keyset key_set{node.keys.begin(), node.keys.end(), Comp(ctx)};
1532
4.32k
            if (key_set.size() != keys_count) {
1533
                // It already has duplicates; bail out.
1534
4.32k
                node.has_duplicate_keys = true;
1535
4.32k
                return {};
1536
4.32k
            }
1537
1538
            // Merge the keys from the children into this set.
1539
4.32k
            for (auto& sub : subs) {
1540
4.32k
                keys_count += sub->size();
1541
                // Small optimization: std::set::merge is linear in the size of the second arg but
1542
                // logarithmic in the size of the first.
1543
4.32k
                if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1544
4.32k
                key_set.merge(*sub);
1545
4.32k
                if (key_set.size() != keys_count) {
1546
4.32k
                    node.has_duplicate_keys = true;
1547
4.32k
                    return {};
1548
4.32k
                }
1549
4.32k
            }
1550
1551
4.32k
            node.has_duplicate_keys = false;
1552
4.32k
            return key_set;
1553
4.32k
        };
1554
1555
4.32k
        TreeEval<state>(upfn);
1556
4.32k
    }
void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const
Line
Count
Source
1501
215
    {
1502
        // We cannot use a lambda here, as lambdas are non assignable, and the set operations
1503
        // below require moving the comparators around.
1504
215
        struct Comp {
1505
215
            const Ctx* ctx_ptr;
1506
215
            Comp(const Ctx& ctx) : ctx_ptr(&ctx) {}
1507
215
            bool operator()(const Key& a, const Key& b) const { return ctx_ptr->KeyCompare(a, b); }
1508
215
        };
1509
1510
        // state in the recursive computation:
1511
        // - std::nullopt means "this node has duplicates"
1512
        // - an std::set means "this node has no duplicate keys, and they are: ...".
1513
215
        using keyset = std::set<Key, Comp>;
1514
215
        using state = std::optional<keyset>;
1515
1516
215
        auto upfn = [&ctx](const Node& node, std::span<state> subs) -> state {
1517
            // If this node is already known to have duplicates, nothing left to do.
1518
215
            if (node.has_duplicate_keys.has_value() && *node.has_duplicate_keys) return {};
1519
1520
            // Check if one of the children is already known to have duplicates.
1521
215
            for (auto& sub : subs) {
1522
215
                if (!sub.has_value()) {
1523
215
                    node.has_duplicate_keys = true;
1524
215
                    return {};
1525
215
                }
1526
215
            }
1527
1528
            // Start building the set of keys involved in this node and children.
1529
            // Start by keys in this node directly.
1530
215
            size_t keys_count = node.keys.size();
1531
215
            keyset key_set{node.keys.begin(), node.keys.end(), Comp(ctx)};
1532
215
            if (key_set.size() != keys_count) {
1533
                // It already has duplicates; bail out.
1534
215
                node.has_duplicate_keys = true;
1535
215
                return {};
1536
215
            }
1537
1538
            // Merge the keys from the children into this set.
1539
215
            for (auto& sub : subs) {
1540
215
                keys_count += sub->size();
1541
                // Small optimization: std::set::merge is linear in the size of the second arg but
1542
                // logarithmic in the size of the first.
1543
215
                if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1544
215
                key_set.merge(*sub);
1545
215
                if (key_set.size() != keys_count) {
1546
215
                    node.has_duplicate_keys = true;
1547
215
                    return {};
1548
215
                }
1549
215
            }
1550
1551
215
            node.has_duplicate_keys = false;
1552
215
            return key_set;
1553
215
        };
1554
1555
215
        TreeEval<state>(upfn);
1556
215
    }
1557
1558
    //! Return the size of the script for this expression (faster than ToScript().size()).
1559
6.43M
    size_t ScriptSize() const { return scriptlen; }
miniscript::Node<CPubKey>::ScriptSize() const
Line
Count
Source
1559
57.5k
    size_t ScriptSize() const { return scriptlen; }
miniscript::Node<unsigned int>::ScriptSize() const
Line
Count
Source
1559
2.39M
    size_t ScriptSize() const { return scriptlen; }
miniscript::Node<XOnlyPubKey>::ScriptSize() const
Line
Count
Source
1559
3.97M
    size_t ScriptSize() const { return scriptlen; }
1560
1561
    //! Return the maximum number of ops needed to satisfy this script non-malleably.
1562
2.17k
    std::optional<uint32_t> GetOps() const {
1563
2.17k
        if (!ops.sat.Valid()) return {};
1564
2.16k
        return ops.count + ops.sat.Value();
1565
2.17k
    }
miniscript::Node<CPubKey>::GetOps() const
Line
Count
Source
1562
1.63k
    std::optional<uint32_t> GetOps() const {
1563
1.63k
        if (!ops.sat.Valid()) return {};
1564
1.62k
        return ops.count + ops.sat.Value();
1565
1.63k
    }
miniscript::Node<unsigned int>::GetOps() const
Line
Count
Source
1562
540
    std::optional<uint32_t> GetOps() const {
1563
540
        if (!ops.sat.Valid()) return {};
1564
537
        return ops.count + ops.sat.Value();
1565
540
    }
1566
1567
    //! Return the number of ops in the script (not counting the dynamic ones that depend on execution).
1568
    uint32_t GetStaticOps() const { return ops.count; }
1569
1570
    //! Check the ops limit of this script against the consensus limit.
1571
6.37k
    bool CheckOpsLimit() const {
1572
6.37k
        if (IsTapscript(m_script_ctx)) return true;
1573
2.05k
        if (const auto ops = GetOps()) return *ops <= MAX_OPS_PER_SCRIPT;
1574
12
        return true;
1575
2.05k
    }
miniscript::Node<CPubKey>::CheckOpsLimit() const
Line
Count
Source
1571
5.48k
    bool CheckOpsLimit() const {
1572
5.48k
        if (IsTapscript(m_script_ctx)) return true;
1573
1.51k
        if (const auto ops = GetOps()) return *ops <= MAX_OPS_PER_SCRIPT;
1574
9
        return true;
1575
1.51k
    }
miniscript::Node<unsigned int>::CheckOpsLimit() const
Line
Count
Source
1571
883
    bool CheckOpsLimit() const {
1572
883
        if (IsTapscript(m_script_ctx)) return true;
1573
540
        if (const auto ops = GetOps()) return *ops <= MAX_OPS_PER_SCRIPT;
1574
3
        return true;
1575
540
    }
1576
1577
    /** Whether this node is of type B, K or W. (That is, anything but V.) */
1578
7.16k
    bool IsBKW() const {
1579
7.16k
        return !((GetType() & "BKW"_mst) == ""_mst);
1580
7.16k
    }
miniscript::Node<CPubKey>::IsBKW() const
Line
Count
Source
1578
5.98k
    bool IsBKW() const {
1579
5.98k
        return !((GetType() & "BKW"_mst) == ""_mst);
1580
5.98k
    }
miniscript::Node<unsigned int>::IsBKW() const
Line
Count
Source
1578
1.17k
    bool IsBKW() const {
1579
1.17k
        return !((GetType() & "BKW"_mst) == ""_mst);
1580
1.17k
    }
1581
1582
    /** Return the maximum number of stack elements needed to satisfy this script non-malleably. */
1583
2.74k
    std::optional<uint32_t> GetStackSize() const {
1584
2.74k
        if (!ss.Sat().Valid()) return {};
1585
2.73k
        return ss.Sat().NetDiff() + static_cast<int32_t>(IsBKW());
1586
2.74k
    }
miniscript::Node<CPubKey>::GetStackSize() const
Line
Count
Source
1583
1.90k
    std::optional<uint32_t> GetStackSize() const {
1584
1.90k
        if (!ss.Sat().Valid()) return {};
1585
1.90k
        return ss.Sat().NetDiff() + static_cast<int32_t>(IsBKW());
1586
1.90k
    }
miniscript::Node<unsigned int>::GetStackSize() const
Line
Count
Source
1583
840
    std::optional<uint32_t> GetStackSize() const {
1584
840
        if (!ss.Sat().Valid()) return {};
1585
836
        return ss.Sat().NetDiff() + static_cast<int32_t>(IsBKW());
1586
840
    }
1587
1588
    //! Return the maximum size of the stack during execution of this script.
1589
4.44k
    std::optional<uint32_t> GetExecStackSize() const {
1590
4.44k
        if (!ss.Sat().Valid()) return {};
1591
4.43k
        return ss.Sat().Exec() + static_cast<int32_t>(IsBKW());
1592
4.44k
    }
miniscript::Node<CPubKey>::GetExecStackSize() const
Line
Count
Source
1589
4.09k
    std::optional<uint32_t> GetExecStackSize() const {
1590
4.09k
        if (!ss.Sat().Valid()) return {};
1591
4.08k
        return ss.Sat().Exec() + static_cast<int32_t>(IsBKW());
1592
4.09k
    }
miniscript::Node<unsigned int>::GetExecStackSize() const
Line
Count
Source
1589
343
    std::optional<uint32_t> GetExecStackSize() const {
1590
343
        if (!ss.Sat().Valid()) return {};
1591
343
        return ss.Sat().Exec() + static_cast<int32_t>(IsBKW());
1592
343
    }
1593
1594
    //! Check the maximum stack size for this script against the policy limit.
1595
6.37k
    bool CheckStackSize() const {
1596
        // Since in Tapscript there is no standardness limit on the script and witness sizes, we may run
1597
        // into the maximum stack size while executing the script. Make sure it doesn't happen.
1598
6.37k
        if (IsTapscript(m_script_ctx)) {
1599
4.31k
            if (const auto exec_ss = GetExecStackSize()) return exec_ss <= MAX_STACK_SIZE;
1600
9
            return true;
1601
4.31k
        }
1602
2.05k
        if (const auto ss = GetStackSize()) return *ss <= MAX_STANDARD_P2WSH_STACK_ITEMS;
1603
12
        return true;
1604
2.05k
    }
miniscript::Node<CPubKey>::CheckStackSize() const
Line
Count
Source
1595
5.48k
    bool CheckStackSize() const {
1596
        // Since in Tapscript there is no standardness limit on the script and witness sizes, we may run
1597
        // into the maximum stack size while executing the script. Make sure it doesn't happen.
1598
5.48k
        if (IsTapscript(m_script_ctx)) {
1599
3.97k
            if (const auto exec_ss = GetExecStackSize()) return exec_ss <= MAX_STACK_SIZE;
1600
9
            return true;
1601
3.97k
        }
1602
1.51k
        if (const auto ss = GetStackSize()) return *ss <= MAX_STANDARD_P2WSH_STACK_ITEMS;
1603
9
        return true;
1604
1.51k
    }
miniscript::Node<unsigned int>::CheckStackSize() const
Line
Count
Source
1595
883
    bool CheckStackSize() const {
1596
        // Since in Tapscript there is no standardness limit on the script and witness sizes, we may run
1597
        // into the maximum stack size while executing the script. Make sure it doesn't happen.
1598
883
        if (IsTapscript(m_script_ctx)) {
1599
343
            if (const auto exec_ss = GetExecStackSize()) return exec_ss <= MAX_STACK_SIZE;
1600
0
            return true;
1601
343
        }
1602
540
        if (const auto ss = GetStackSize()) return *ss <= MAX_STANDARD_P2WSH_STACK_ITEMS;
1603
3
        return true;
1604
540
    }
1605
1606
    //! Whether no satisfaction exists for this node.
1607
166
    bool IsNotSatisfiable() const { return !GetStackSize(); }
1608
1609
    /** Return the maximum size in bytes of a witness to satisfy this script non-malleably. Note this does
1610
     * not include the witness script push. */
1611
529
    std::optional<uint32_t> GetWitnessSize() const {
1612
529
        if (!ws.sat.Valid()) return {};
1613
529
        return ws.sat.Value();
1614
529
    }
miniscript::Node<CPubKey>::GetWitnessSize() const
Line
Count
Source
1611
379
    std::optional<uint32_t> GetWitnessSize() const {
1612
379
        if (!ws.sat.Valid()) return {};
1613
379
        return ws.sat.Value();
1614
379
    }
miniscript::Node<unsigned int>::GetWitnessSize() const
Line
Count
Source
1611
150
    std::optional<uint32_t> GetWitnessSize() const {
1612
150
        if (!ws.sat.Valid()) return {};
1613
150
        return ws.sat.Value();
1614
150
    }
1615
1616
    //! Return the expression type.
1617
64.3M
    Type GetType() const { return typ; }
miniscript::Node<CPubKey>::GetType() const
Line
Count
Source
1617
24.3M
    Type GetType() const { return typ; }
miniscript::Node<unsigned int>::GetType() const
Line
Count
Source
1617
4.13M
    Type GetType() const { return typ; }
miniscript::Node<XOnlyPubKey>::GetType() const
Line
Count
Source
1617
35.7M
    Type GetType() const { return typ; }
1618
1619
    //! Return the script context for this node.
1620
1.50k
    MiniscriptContext GetMsCtx() const { return m_script_ctx; }
1621
1622
    //! Find an insane subnode which has no insane children. Nullptr if there is none.
1623
15
    const Node* FindInsaneSub() const {
1624
114
        return TreeEval<const Node*>([](const Node& node, std::span<const Node*> subs) -> const Node* {
1625
114
            for (auto& sub: subs) if (sub) return sub;
1626
103
            if (!node.IsSaneSubexpression()) return &node;
1627
92
            return nullptr;
1628
103
        });
miniscript::Node<CPubKey>::FindInsaneSub() const::'lambda'(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>)::operator()(miniscript::Node<CPubKey> const&, std::span<miniscript::Node<CPubKey> const*, 18446744073709551615ul>) const
Line
Count
Source
1624
7
        return TreeEval<const Node*>([](const Node& node, std::span<const Node*> subs) -> const Node* {
1625
7
            for (auto& sub: subs) if (sub) return sub;
1626
6
            if (!node.IsSaneSubexpression()) return &node;
1627
5
            return nullptr;
1628
6
        });
miniscript::Node<unsigned int>::FindInsaneSub() const::'lambda'(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>)::operator()(miniscript::Node<unsigned int> const&, std::span<miniscript::Node<unsigned int> const*, 18446744073709551615ul>) const
Line
Count
Source
1624
107
        return TreeEval<const Node*>([](const Node& node, std::span<const Node*> subs) -> const Node* {
1625
107
            for (auto& sub: subs) if (sub) return sub;
1626
97
            if (!node.IsSaneSubexpression()) return &node;
1627
87
            return nullptr;
1628
97
        });
1629
15
    }
miniscript::Node<CPubKey>::FindInsaneSub() const
Line
Count
Source
1623
1
    const Node* FindInsaneSub() const {
1624
1
        return TreeEval<const Node*>([](const Node& node, std::span<const Node*> subs) -> const Node* {
1625
1
            for (auto& sub: subs) if (sub) return sub;
1626
1
            if (!node.IsSaneSubexpression()) return &node;
1627
1
            return nullptr;
1628
1
        });
1629
1
    }
miniscript::Node<unsigned int>::FindInsaneSub() const
Line
Count
Source
1623
14
    const Node* FindInsaneSub() const {
1624
14
        return TreeEval<const Node*>([](const Node& node, std::span<const Node*> subs) -> const Node* {
1625
14
            for (auto& sub: subs) if (sub) return sub;
1626
14
            if (!node.IsSaneSubexpression()) return &node;
1627
14
            return nullptr;
1628
14
        });
1629
14
    }
1630
1631
    //! Determine whether a Miniscript node is satisfiable. fn(node) will be invoked for all
1632
    //! key, time, and hashing nodes, and should return their satisfiability.
1633
    template<typename F>
1634
    bool IsSatisfiable(F fn) const
1635
375
    {
1636
        // TreeEval() doesn't support bool as NodeType, so use int instead.
1637
25.4k
        return TreeEval<int>([&fn](const Node& node, std::span<int> subs) -> bool {
1638
25.4k
            switch (node.fragment) {
1639
249
                case Fragment::JUST_0:
1640
249
                    return false;
1641
231
                case Fragment::JUST_1:
1642
231
                    return true;
1643
1.36k
                case Fragment::PK_K:
1644
1.44k
                case Fragment::PK_H:
1645
1.47k
                case Fragment::MULTI:
1646
1.48k
                case Fragment::MULTI_A:
1647
1.67k
                case Fragment::AFTER:
1648
7.79k
                case Fragment::OLDER:
1649
7.83k
                case Fragment::HASH256:
1650
7.85k
                case Fragment::HASH160:
1651
7.91k
                case Fragment::SHA256:
1652
7.93k
                case Fragment::RIPEMD160:
1653
7.93k
                    return bool{fn(node)};
1654
87
                case Fragment::ANDOR:
1655
87
                    return (subs[0] && subs[1]) || subs[2];
1656
198
                case Fragment::AND_V:
1657
7.45k
                case Fragment::AND_B:
1658
7.45k
                    return subs[0] && subs[1];
1659
24
                case Fragment::OR_B:
1660
42
                case Fragment::OR_C:
1661
87
                case Fragment::OR_D:
1662
324
                case Fragment::OR_I:
1663
324
                    return subs[0] || subs[1];
1664
48
                case Fragment::THRESH:
1665
48
                    return static_cast<uint32_t>(std::count(subs.begin(), subs.end(), true)) >= node.k;
1666
9.08k
                default: // wrappers
1667
9.08k
                    assert(subs.size() >= 1);
1668
9.08k
                    CHECK_NONFATAL(subs.size() == 1);
1669
9.08k
                    return subs[0];
1670
25.4k
            }
1671
25.4k
        });
1672
375
    }
1673
1674
    //! Check whether this node is valid at all.
1675
2.70M
    bool IsValid() const {
1676
2.70M
        if (GetType() == ""_mst) return false;
1677
2.70M
        return ScriptSize() <= internal::MaxScriptSize(m_script_ctx);
1678
2.70M
    }
miniscript::Node<CPubKey>::IsValid() const
Line
Count
Source
1675
31.1k
    bool IsValid() const {
1676
31.1k
        if (GetType() == ""_mst) return false;
1677
31.0k
        return ScriptSize() <= internal::MaxScriptSize(m_script_ctx);
1678
31.1k
    }
miniscript::Node<unsigned int>::IsValid() const
Line
Count
Source
1675
673k
    bool IsValid() const {
1676
673k
        if (GetType() == ""_mst) return false;
1677
673k
        return ScriptSize() <= internal::MaxScriptSize(m_script_ctx);
1678
673k
    }
miniscript::Node<XOnlyPubKey>::IsValid() const
Line
Count
Source
1675
1.99M
    bool IsValid() const {
1676
1.99M
        if (GetType() == ""_mst) return false;
1677
1.99M
        return ScriptSize() <= internal::MaxScriptSize(m_script_ctx);
1678
1.99M
    }
1679
1680
    //! Check whether this node is valid as a script on its own.
1681
11.3k
    bool IsValidTopLevel() const { return IsValid() && GetType() << "B"_mst; }
miniscript::Node<CPubKey>::IsValidTopLevel() const
Line
Count
Source
1681
5.67k
    bool IsValidTopLevel() const { return IsValid() && GetType() << "B"_mst; }
miniscript::Node<unsigned int>::IsValidTopLevel() const
Line
Count
Source
1681
1.40k
    bool IsValidTopLevel() const { return IsValid() && GetType() << "B"_mst; }
miniscript::Node<XOnlyPubKey>::IsValidTopLevel() const
Line
Count
Source
1681
4.32k
    bool IsValidTopLevel() const { return IsValid() && GetType() << "B"_mst; }
1682
1683
    //! Check whether this script can always be satisfied in a non-malleable way.
1684
6.20k
    bool IsNonMalleable() const { return GetType() << "m"_mst; }
miniscript::Node<CPubKey>::IsNonMalleable() const
Line
Count
Source
1684
5.31k
    bool IsNonMalleable() const { return GetType() << "m"_mst; }
miniscript::Node<unsigned int>::IsNonMalleable() const
Line
Count
Source
1684
892
    bool IsNonMalleable() const { return GetType() << "m"_mst; }
1685
1686
    //! Check whether this script always needs a signature.
1687
4.76k
    bool NeedsSignature() const { return GetType() << "s"_mst; }
miniscript::Node<CPubKey>::NeedsSignature() const
Line
Count
Source
1687
3.98k
    bool NeedsSignature() const { return GetType() << "s"_mst; }
miniscript::Node<unsigned int>::NeedsSignature() const
Line
Count
Source
1687
783
    bool NeedsSignature() const { return GetType() << "s"_mst; }
1688
1689
    //! Check whether there is no satisfaction path that contains both timelocks and heightlocks
1690
5.03k
    bool CheckTimeLocksMix() const { return GetType() << "k"_mst; }
miniscript::Node<CPubKey>::CheckTimeLocksMix() const
Line
Count
Source
1690
4.15k
    bool CheckTimeLocksMix() const { return GetType() << "k"_mst; }
miniscript::Node<unsigned int>::CheckTimeLocksMix() const
Line
Count
Source
1690
881
    bool CheckTimeLocksMix() const { return GetType() << "k"_mst; }
1691
1692
    //! Check whether there is no duplicate key across this fragment and all its sub-fragments.
1693
4.77k
    bool CheckDuplicateKey() const { return has_duplicate_keys && !*has_duplicate_keys; }
miniscript::Node<CPubKey>::CheckDuplicateKey() const
Line
Count
Source
1693
3.89k
    bool CheckDuplicateKey() const { return has_duplicate_keys && !*has_duplicate_keys; }
miniscript::Node<unsigned int>::CheckDuplicateKey() const
Line
Count
Source
1693
873
    bool CheckDuplicateKey() const { return has_duplicate_keys && !*has_duplicate_keys; }
1694
1695
    //! Whether successful non-malleable satisfactions are guaranteed to be valid.
1696
6.37k
    bool ValidSatisfactions() const { return IsValid() && CheckOpsLimit() && CheckStackSize(); }
miniscript::Node<CPubKey>::ValidSatisfactions() const
Line
Count
Source
1696
5.48k
    bool ValidSatisfactions() const { return IsValid() && CheckOpsLimit() && CheckStackSize(); }
miniscript::Node<unsigned int>::ValidSatisfactions() const
Line
Count
Source
1696
887
    bool ValidSatisfactions() const { return IsValid() && CheckOpsLimit() && CheckStackSize(); }
1697
1698
    //! Whether the apparent policy of this node matches its script semantics. Doesn't guarantee it is a safe script on its own.
1699
6.09k
    bool IsSaneSubexpression() const { return ValidSatisfactions() && IsNonMalleable() && CheckTimeLocksMix() && CheckDuplicateKey(); }
miniscript::Node<CPubKey>::IsSaneSubexpression() const
Line
Count
Source
1699
5.21k
    bool IsSaneSubexpression() const { return ValidSatisfactions() && IsNonMalleable() && CheckTimeLocksMix() && CheckDuplicateKey(); }
miniscript::Node<unsigned int>::IsSaneSubexpression() const
Line
Count
Source
1699
887
    bool IsSaneSubexpression() const { return ValidSatisfactions() && IsNonMalleable() && CheckTimeLocksMix() && CheckDuplicateKey(); }
1700
1701
    //! Check whether this node is safe as a script on its own.
1702
5.99k
    bool IsSane() const { return IsValidTopLevel() && IsSaneSubexpression() && NeedsSignature(); }
miniscript::Node<CPubKey>::IsSane() const
Line
Count
Source
1702
5.20k
    bool IsSane() const { return IsValidTopLevel() && IsSaneSubexpression() && NeedsSignature(); }
miniscript::Node<unsigned int>::IsSane() const
Line
Count
Source
1702
794
    bool IsSane() const { return IsValidTopLevel() && IsSaneSubexpression() && NeedsSignature(); }
1703
1704
    //! Produce a witness for this script, if possible and given the information available in the context.
1705
    //! The non-malleable satisfaction is guaranteed to be valid if it exists, and ValidSatisfaction()
1706
    //! is true. If IsSane() holds, this satisfaction is guaranteed to succeed in case the node's
1707
    //! conditions are satisfied (private keys and hash preimages available, locktimes satisfied).
1708
    template<typename Ctx>
1709
9.36k
    Availability Satisfy(const Ctx& ctx, std::vector<std::vector<unsigned char>>& stack, bool nonmalleable = true) const {
1710
9.36k
        auto ret = ProduceInput(ctx);
1711
9.36k
        if (nonmalleable && (ret.sat.malleable || !ret.sat.has_sig)) return Availability::NO;
1712
3.45k
        stack = std::move(ret.sat.stack);
1713
3.45k
        return ret.sat.available;
1714
9.36k
    }
miniscript_tests.cpp:miniscript::Availability miniscript::Node<CPubKey>::Satisfy<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&, std::vector<std::vector<unsigned char, std::allocator<unsigned char>>, std::allocator<std::vector<unsigned char, std::allocator<unsigned char>>>>&, bool) const
Line
Count
Source
1709
4.82k
    Availability Satisfy(const Ctx& ctx, std::vector<std::vector<unsigned char>>& stack, bool nonmalleable = true) const {
1710
4.82k
        auto ret = ProduceInput(ctx);
1711
4.82k
        if (nonmalleable && (ret.sat.malleable || !ret.sat.has_sig)) return Availability::NO;
1712
2.68k
        stack = std::move(ret.sat.stack);
1713
2.68k
        return ret.sat.available;
1714
4.82k
    }
miniscript::Availability miniscript::Node<XOnlyPubKey>::Satisfy<TapSatisfier>(TapSatisfier const&, std::vector<std::vector<unsigned char, std::allocator<unsigned char>>, std::allocator<std::vector<unsigned char, std::allocator<unsigned char>>>>&, bool) const
Line
Count
Source
1709
4.32k
    Availability Satisfy(const Ctx& ctx, std::vector<std::vector<unsigned char>>& stack, bool nonmalleable = true) const {
1710
4.32k
        auto ret = ProduceInput(ctx);
1711
4.32k
        if (nonmalleable && (ret.sat.malleable || !ret.sat.has_sig)) return Availability::NO;
1712
686
        stack = std::move(ret.sat.stack);
1713
686
        return ret.sat.available;
1714
4.32k
    }
miniscript::Availability miniscript::Node<CPubKey>::Satisfy<WshSatisfier>(WshSatisfier const&, std::vector<std::vector<unsigned char, std::allocator<unsigned char>>, std::allocator<std::vector<unsigned char, std::allocator<unsigned char>>>>&, bool) const
Line
Count
Source
1709
215
    Availability Satisfy(const Ctx& ctx, std::vector<std::vector<unsigned char>>& stack, bool nonmalleable = true) const {
1710
215
        auto ret = ProduceInput(ctx);
1711
215
        if (nonmalleable && (ret.sat.malleable || !ret.sat.has_sig)) return Availability::NO;
1712
84
        stack = std::move(ret.sat.stack);
1713
84
        return ret.sat.available;
1714
215
    }
1715
1716
    //! Equality testing.
1717
    bool operator==(const Node<Key>& arg) const { return Compare(*this, arg) == 0; }
1718
1719
    // Constructors with various argument combinations, which bypass the duplicate key check.
1720
    Node(internal::NoDupCheck, MiniscriptContext script_ctx, enum Fragment nt, std::vector<Node> sub, std::vector<unsigned char> arg, uint32_t val = 0)
1721
        : fragment(nt), k(val), data(std::move(arg)), subs(std::move(sub)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1722
    Node(internal::NoDupCheck, MiniscriptContext script_ctx, enum Fragment nt, std::vector<unsigned char> arg, uint32_t val = 0)
1723
355
        : fragment(nt), k(val), data(std::move(arg)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
miniscript::Node<CPubKey>::Node(miniscript::internal::NoDupCheck, miniscript::MiniscriptContext, miniscript::Fragment, std::vector<unsigned char, std::allocator<unsigned char>>, unsigned int)
Line
Count
Source
1723
150
        : fragment(nt), k(val), data(std::move(arg)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
miniscript::Node<unsigned int>::Node(miniscript::internal::NoDupCheck, miniscript::MiniscriptContext, miniscript::Fragment, std::vector<unsigned char, std::allocator<unsigned char>>, unsigned int)
Line
Count
Source
1723
193
        : fragment(nt), k(val), data(std::move(arg)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
miniscript::Node<XOnlyPubKey>::Node(miniscript::internal::NoDupCheck, miniscript::MiniscriptContext, miniscript::Fragment, std::vector<unsigned char, std::allocator<unsigned char>>, unsigned int)
Line
Count
Source
1723
12
        : fragment(nt), k(val), data(std::move(arg)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1724
    Node(internal::NoDupCheck, MiniscriptContext script_ctx, enum Fragment nt, std::vector<Node> sub, std::vector<Key> key, uint32_t val = 0)
1725
        : fragment(nt), k(val), keys(std::move(key)), m_script_ctx{script_ctx}, subs(std::move(sub)), ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1726
    Node(internal::NoDupCheck, MiniscriptContext script_ctx, enum Fragment nt, std::vector<Key> key, uint32_t val = 0)
1727
8.05k
        : fragment(nt), k(val), keys(std::move(key)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
miniscript::Node<CPubKey>::Node(miniscript::internal::NoDupCheck, miniscript::MiniscriptContext, miniscript::Fragment, std::vector<CPubKey, std::allocator<CPubKey>>, unsigned int)
Line
Count
Source
1727
1.85k
        : fragment(nt), k(val), keys(std::move(key)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
miniscript::Node<unsigned int>::Node(miniscript::internal::NoDupCheck, miniscript::MiniscriptContext, miniscript::Fragment, std::vector<unsigned int, std::allocator<unsigned int>>, unsigned int)
Line
Count
Source
1727
1.70k
        : fragment(nt), k(val), keys(std::move(key)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
miniscript::Node<XOnlyPubKey>::Node(miniscript::internal::NoDupCheck, miniscript::MiniscriptContext, miniscript::Fragment, std::vector<XOnlyPubKey, std::allocator<XOnlyPubKey>>, unsigned int)
Line
Count
Source
1727
4.49k
        : fragment(nt), k(val), keys(std::move(key)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1728
    Node(internal::NoDupCheck, MiniscriptContext script_ctx, enum Fragment nt, std::vector<Node> sub, uint32_t val = 0)
1729
3.19M
        : fragment(nt), k(val), subs(std::move(sub)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
miniscript::Node<CPubKey>::Node(miniscript::internal::NoDupCheck, miniscript::MiniscriptContext, miniscript::Fragment, std::vector<miniscript::Node<CPubKey>, std::allocator<miniscript::Node<CPubKey>>>, unsigned int)
Line
Count
Source
1729
17.7k
        : fragment(nt), k(val), subs(std::move(sub)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
miniscript::Node<unsigned int>::Node(miniscript::internal::NoDupCheck, miniscript::MiniscriptContext, miniscript::Fragment, std::vector<miniscript::Node<unsigned int>, std::allocator<miniscript::Node<unsigned int>>>, unsigned int)
Line
Count
Source
1729
1.19M
        : fragment(nt), k(val), subs(std::move(sub)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
miniscript::Node<XOnlyPubKey>::Node(miniscript::internal::NoDupCheck, miniscript::MiniscriptContext, miniscript::Fragment, std::vector<miniscript::Node<XOnlyPubKey>, std::allocator<miniscript::Node<XOnlyPubKey>>>, unsigned int)
Line
Count
Source
1729
1.98M
        : fragment(nt), k(val), subs(std::move(sub)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1730
    Node(internal::NoDupCheck, MiniscriptContext script_ctx, enum Fragment nt, uint32_t val = 0)
1731
10.2k
        : fragment(nt), k(val), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
miniscript::Node<CPubKey>::Node(miniscript::internal::NoDupCheck, miniscript::MiniscriptContext, miniscript::Fragment, unsigned int)
Line
Count
Source
1731
8.63k
        : fragment(nt), k(val), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
miniscript::Node<unsigned int>::Node(miniscript::internal::NoDupCheck, miniscript::MiniscriptContext, miniscript::Fragment, unsigned int)
Line
Count
Source
1731
769
        : fragment(nt), k(val), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
miniscript::Node<XOnlyPubKey>::Node(miniscript::internal::NoDupCheck, miniscript::MiniscriptContext, miniscript::Fragment, unsigned int)
Line
Count
Source
1731
840
        : fragment(nt), k(val), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1732
1733
    // Constructors with various argument combinations, which do perform the duplicate key check.
1734
    template <typename Ctx> Node(const Ctx& ctx, enum Fragment nt, std::vector<Node> sub, std::vector<unsigned char> arg, uint32_t val = 0)
1735
        : Node(internal::NoDupCheck{}, ctx.MsContext(), nt, std::move(sub), std::move(arg), val) { DuplicateKeyCheck(ctx); }
1736
    template <typename Ctx> Node(const Ctx& ctx, enum Fragment nt, std::vector<unsigned char> arg, uint32_t val = 0)
1737
        : Node(internal::NoDupCheck{}, ctx.MsContext(), nt, std::move(arg), val) { DuplicateKeyCheck(ctx);}
1738
    template <typename Ctx> Node(const Ctx& ctx, enum Fragment nt, std::vector<Node> sub, std::vector<Key> key, uint32_t val = 0)
1739
        : Node(internal::NoDupCheck{}, ctx.MsContext(), nt, std::move(sub), std::move(key), val) { DuplicateKeyCheck(ctx); }
1740
    template <typename Ctx> Node(const Ctx& ctx, enum Fragment nt, std::vector<Key> key, uint32_t val = 0)
1741
        : Node(internal::NoDupCheck{}, ctx.MsContext(), nt, std::move(key), val) { DuplicateKeyCheck(ctx); }
1742
    template <typename Ctx> Node(const Ctx& ctx, enum Fragment nt, std::vector<Node> sub, uint32_t val = 0)
1743
        : Node(internal::NoDupCheck{}, ctx.MsContext(), nt, std::move(sub), val) { DuplicateKeyCheck(ctx); }
1744
    template <typename Ctx> Node(const Ctx& ctx, enum Fragment nt, uint32_t val = 0)
1745
        : Node(internal::NoDupCheck{}, ctx.MsContext(), nt, val) { DuplicateKeyCheck(ctx); }
1746
1747
    // Delete copy constructor and assignment operator, use Clone() instead
1748
    Node(const Node&) = delete;
1749
    Node& operator=(const Node&) = delete;
1750
1751
    // subs is movable, circumventing recursion, so these are permitted.
1752
4.83M
    Node(Node&&) noexcept = default;
miniscript::Node<CPubKey>::Node(miniscript::Node<CPubKey>&&)
Line
Count
Source
1752
45.0k
    Node(Node&&) noexcept = default;
miniscript::Node<unsigned int>::Node(miniscript::Node<unsigned int>&&)
Line
Count
Source
1752
2.79M
    Node(Node&&) noexcept = default;
miniscript::Node<XOnlyPubKey>::Node(miniscript::Node<XOnlyPubKey>&&)
Line
Count
Source
1752
1.99M
    Node(Node&&) noexcept = default;
1753
3.19M
    Node& operator=(Node&&) noexcept = default;
miniscript::Node<unsigned int>::operator=(miniscript::Node<unsigned int>&&)
Line
Count
Source
1753
1.19M
    Node& operator=(Node&&) noexcept = default;
miniscript::Node<CPubKey>::operator=(miniscript::Node<CPubKey>&&)
Line
Count
Source
1753
16.9k
    Node& operator=(Node&&) noexcept = default;
miniscript::Node<XOnlyPubKey>::operator=(miniscript::Node<XOnlyPubKey>&&)
Line
Count
Source
1753
1.98M
    Node& operator=(Node&&) noexcept = default;
1754
};
1755
1756
namespace internal {
1757
1758
enum class ParseContext {
1759
    /** An expression which may be begin with wrappers followed by a colon. */
1760
    WRAPPED_EXPR,
1761
    /** A miniscript expression which does not begin with wrappers. */
1762
    EXPR,
1763
1764
    /** SWAP wraps the top constructed node with s: */
1765
    SWAP,
1766
    /** ALT wraps the top constructed node with a: */
1767
    ALT,
1768
    /** CHECK wraps the top constructed node with c: */
1769
    CHECK,
1770
    /** DUP_IF wraps the top constructed node with d: */
1771
    DUP_IF,
1772
    /** VERIFY wraps the top constructed node with v: */
1773
    VERIFY,
1774
    /** NON_ZERO wraps the top constructed node with j: */
1775
    NON_ZERO,
1776
    /** ZERO_NOTEQUAL wraps the top constructed node with n: */
1777
    ZERO_NOTEQUAL,
1778
    /** WRAP_U will construct an or_i(X,0) node from the top constructed node. */
1779
    WRAP_U,
1780
    /** WRAP_T will construct an and_v(X,1) node from the top constructed node. */
1781
    WRAP_T,
1782
1783
    /** AND_N will construct an andor(X,Y,0) node from the last two constructed nodes. */
1784
    AND_N,
1785
    /** AND_V will construct an and_v node from the last two constructed nodes. */
1786
    AND_V,
1787
    /** AND_B will construct an and_b node from the last two constructed nodes. */
1788
    AND_B,
1789
    /** ANDOR will construct an andor node from the last three constructed nodes. */
1790
    ANDOR,
1791
    /** OR_B will construct an or_b node from the last two constructed nodes. */
1792
    OR_B,
1793
    /** OR_C will construct an or_c node from the last two constructed nodes. */
1794
    OR_C,
1795
    /** OR_D will construct an or_d node from the last two constructed nodes. */
1796
    OR_D,
1797
    /** OR_I will construct an or_i node from the last two constructed nodes. */
1798
    OR_I,
1799
1800
    /** THRESH will read a wrapped expression, and then look for a COMMA. If
1801
     * no comma follows, it will construct a thresh node from the appropriate
1802
     * number of constructed children. Otherwise, it will recurse with another
1803
     * THRESH. */
1804
    THRESH,
1805
1806
    /** COMMA expects the next element to be ',' and fails if not. */
1807
    COMMA,
1808
    /** CLOSE_BRACKET expects the next element to be ')' and fails if not. */
1809
    CLOSE_BRACKET,
1810
};
1811
1812
int FindNextChar(std::span<const char> in, char m);
1813
1814
/** Parse a key expression fully contained within a fragment with the name given by 'func' */
1815
template<typename Key, typename Ctx>
1816
std::optional<Key> ParseKey(const std::string& func, std::span<const char>& in, const Ctx& ctx)
1817
1.16k
{
1818
1.16k
    std::span<const char> expr = script::Expr(in);
1819
1.16k
    if (!script::Func(func, expr)) return {};
1820
1.15k
    return ctx.FromString(expr);
1821
1.16k
}
miniscript_tests.cpp:std::optional<CPubKey> miniscript::internal::ParseKey<CPubKey, (anonymous namespace)::KeyConverter>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&, std::span<char const, 18446744073709551615ul>&, (anonymous namespace)::KeyConverter const&)
Line
Count
Source
1817
794
{
1818
794
    std::span<const char> expr = script::Expr(in);
1819
794
    if (!script::Func(func, expr)) return {};
1820
794
    return ctx.FromString(expr);
1821
794
}
descriptor.cpp:std::optional<unsigned int> miniscript::internal::ParseKey<unsigned int, (anonymous namespace)::KeyParser>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&, std::span<char const, 18446744073709551615ul>&, (anonymous namespace)::KeyParser const&)
Line
Count
Source
1817
367
{
1818
367
    std::span<const char> expr = script::Expr(in);
1819
367
    if (!script::Func(func, expr)) return {};
1820
365
    return ctx.FromString(expr);
1821
367
}
1822
1823
/** Parse a hex string fully contained within a fragment with the name given by 'func' */
1824
template<typename Ctx>
1825
std::optional<std::vector<unsigned char>> ParseHexStr(const std::string& func, std::span<const char>& in, const size_t expected_size,
1826
                                                                         const Ctx& ctx)
1827
89
{
1828
89
    std::span<const char> expr = script::Expr(in);
1829
89
    if (!script::Func(func, expr)) return {};
1830
89
    std::string val = std::string(expr.begin(), expr.end());
1831
89
    if (!IsHex(val)) return {};
1832
89
    auto hash = ParseHex(val);
1833
89
    if (hash.size() != expected_size) return {};
1834
89
    return hash;
1835
89
}
miniscript_tests.cpp:std::optional<std::vector<unsigned char, std::allocator<unsigned char>>> miniscript::internal::ParseHexStr<(anonymous namespace)::KeyConverter>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&, std::span<char const, 18446744073709551615ul>&, unsigned long, (anonymous namespace)::KeyConverter const&)
Line
Count
Source
1827
49
{
1828
49
    std::span<const char> expr = script::Expr(in);
1829
49
    if (!script::Func(func, expr)) return {};
1830
49
    std::string val = std::string(expr.begin(), expr.end());
1831
49
    if (!IsHex(val)) return {};
1832
49
    auto hash = ParseHex(val);
1833
49
    if (hash.size() != expected_size) return {};
1834
49
    return hash;
1835
49
}
descriptor.cpp:std::optional<std::vector<unsigned char, std::allocator<unsigned char>>> miniscript::internal::ParseHexStr<(anonymous namespace)::KeyParser>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&, std::span<char const, 18446744073709551615ul>&, unsigned long, (anonymous namespace)::KeyParser const&)
Line
Count
Source
1827
40
{
1828
40
    std::span<const char> expr = script::Expr(in);
1829
40
    if (!script::Func(func, expr)) return {};
1830
40
    std::string val = std::string(expr.begin(), expr.end());
1831
40
    if (!IsHex(val)) return {};
1832
40
    auto hash = ParseHex(val);
1833
40
    if (hash.size() != expected_size) return {};
1834
40
    return hash;
1835
40
}
1836
1837
/** BuildBack pops the last two elements off `constructed` and wraps them in the specified Fragment */
1838
template<typename Key>
1839
void BuildBack(const MiniscriptContext script_ctx, Fragment nt, std::vector<Node<Key>>& constructed, const bool reverse = false)
1840
9.67k
{
1841
9.67k
    Node<Key> child{std::move(constructed.back())};
1842
9.67k
    constructed.pop_back();
1843
9.67k
    if (reverse) {
1844
4.82k
        constructed.back() = Node<Key>{internal::NoDupCheck{}, script_ctx, nt, Vector(std::move(child), std::move(constructed.back()))};
1845
4.85k
    } else {
1846
4.85k
        constructed.back() = Node<Key>{internal::NoDupCheck{}, script_ctx, nt, Vector(std::move(constructed.back()), std::move(child))};
1847
4.85k
    }
1848
9.67k
}
void miniscript::internal::BuildBack<CPubKey>(miniscript::MiniscriptContext, miniscript::Fragment, std::vector<miniscript::Node<CPubKey>, std::allocator<miniscript::Node<CPubKey>>>&, bool)
Line
Count
Source
1840
7.56k
{
1841
7.56k
    Node<Key> child{std::move(constructed.back())};
1842
7.56k
    constructed.pop_back();
1843
7.56k
    if (reverse) {
1844
2.96k
        constructed.back() = Node<Key>{internal::NoDupCheck{}, script_ctx, nt, Vector(std::move(child), std::move(constructed.back()))};
1845
4.59k
    } else {
1846
4.59k
        constructed.back() = Node<Key>{internal::NoDupCheck{}, script_ctx, nt, Vector(std::move(constructed.back()), std::move(child))};
1847
4.59k
    }
1848
7.56k
}
void miniscript::internal::BuildBack<unsigned int>(miniscript::MiniscriptContext, miniscript::Fragment, std::vector<miniscript::Node<unsigned int>, std::allocator<miniscript::Node<unsigned int>>>&, bool)
Line
Count
Source
1840
1.14k
{
1841
1.14k
    Node<Key> child{std::move(constructed.back())};
1842
1.14k
    constructed.pop_back();
1843
1.14k
    if (reverse) {
1844
884
        constructed.back() = Node<Key>{internal::NoDupCheck{}, script_ctx, nt, Vector(std::move(child), std::move(constructed.back()))};
1845
884
    } else {
1846
261
        constructed.back() = Node<Key>{internal::NoDupCheck{}, script_ctx, nt, Vector(std::move(constructed.back()), std::move(child))};
1847
261
    }
1848
1.14k
}
void miniscript::internal::BuildBack<XOnlyPubKey>(miniscript::MiniscriptContext, miniscript::Fragment, std::vector<miniscript::Node<XOnlyPubKey>, std::allocator<miniscript::Node<XOnlyPubKey>>>&, bool)
Line
Count
Source
1840
972
{
1841
972
    Node<Key> child{std::move(constructed.back())};
1842
972
    constructed.pop_back();
1843
972
    if (reverse) {
1844
972
        constructed.back() = Node<Key>{internal::NoDupCheck{}, script_ctx, nt, Vector(std::move(child), std::move(constructed.back()))};
1845
972
    } else {
1846
0
        constructed.back() = Node<Key>{internal::NoDupCheck{}, script_ctx, nt, Vector(std::move(constructed.back()), std::move(child))};
1847
0
    }
1848
972
}
1849
1850
/**
1851
 * Parse a miniscript from its textual descriptor form.
1852
 * This does not check whether the script is valid, let alone sane. The caller is expected to use
1853
 * the `IsValidTopLevel()` and `IsSaneTopLevel()` to check for these properties on the node.
1854
 */
1855
template <typename Key, typename Ctx>
1856
inline std::optional<Node<Key>> Parse(std::span<const char> in, const Ctx& ctx)
1857
760
{
1858
760
    using namespace script;
1859
1860
    // Account for the minimum script size for all parsed fragments so far. It "borrows" 1
1861
    // script byte from all leaf nodes, counting it instead whenever a space for a recursive
1862
    // expression is added (through andor, and_*, or_*, thresh). This guarantees that all fragments
1863
    // increment the script_size by at least one, except for:
1864
    // - "0", "1": these leafs are only a single byte, so their subtracted-from increment is 0.
1865
    //   This is not an issue however, as "space" for them has to be created by combinators,
1866
    //   which do increment script_size.
1867
    // - "v:": the v wrapper adds nothing as in some cases it results in no opcode being added
1868
    //   (instead transforming another opcode into its VERIFY form). However, the v: wrapper has
1869
    //   to be interleaved with other fragments to be valid, so this is not a concern.
1870
760
    size_t script_size{1};
1871
760
    size_t max_size{internal::MaxScriptSize(ctx.MsContext())};
1872
1873
    // The two integers are used to hold state for thresh()
1874
760
    std::vector<std::tuple<ParseContext, int64_t, int64_t>> to_parse;
1875
760
    std::vector<Node<Key>> constructed;
1876
1877
760
    to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
1878
1879
    // Parses a multi() or multi_a() from its string representation. Returns false on parsing error.
1880
760
    const auto parse_multi_exp = [&](std::span<const char>& in, const bool is_multi_a) -> bool {
1881
59
        const auto max_keys{is_multi_a ? MAX_PUBKEYS_PER_MULTI_A : MAX_PUBKEYS_PER_MULTISIG};
1882
59
        const auto required_ctx{is_multi_a ? MiniscriptContext::TAPSCRIPT : MiniscriptContext::P2WSH};
1883
59
        if (ctx.MsContext() != required_ctx) return false;
1884
        // Get threshold
1885
47
        int next_comma = FindNextChar(in, ',');
1886
47
        if (next_comma < 1) return false;
1887
47
        const auto k_to_integral{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
1888
47
        if (!k_to_integral.has_value()) return false;
1889
46
        const int64_t k{k_to_integral.value()};
1890
46
        in = in.subspan(next_comma + 1);
1891
        // Get keys. It is compatible for both compressed and x-only keys.
1892
46
        std::vector<Key> keys;
1893
175
        while (next_comma != -1) {
1894
129
            next_comma = FindNextChar(in, ',');
1895
129
            int key_length = (next_comma == -1) ? FindNextChar(in, ')') : next_comma;
1896
129
            if (key_length < 1) return false;
1897
129
            std::span<const char> sp{in.begin(), in.begin() + key_length};
1898
129
            auto key = ctx.FromString(sp);
1899
129
            if (!key) return false;
1900
129
            keys.push_back(std::move(*key));
1901
129
            in = in.subspan(key_length + 1);
1902
129
        }
1903
46
        if (keys.size() < 1 || keys.size() > max_keys) return false;
1904
46
        if (k < 1 || k > (int64_t)keys.size()) return false;
1905
46
        if (is_multi_a) {
1906
            // (push + xonly-key + CHECKSIG[ADD]) * n + k + OP_NUMEQUAL(VERIFY), minus one.
1907
16
            script_size += (1 + 32 + 1) * keys.size() + BuildScript(k).size();
1908
16
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), k);
1909
30
        } else {
1910
30
            script_size += 2 + (keys.size() > 16) + (k > 16) + 34 * keys.size();
1911
30
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), k);
1912
30
        }
1913
46
        return true;
1914
46
    };
miniscript_tests.cpp:std::optional<miniscript::Node<CPubKey>> miniscript::internal::Parse<CPubKey, (anonymous namespace)::KeyConverter>(std::span<char const, 18446744073709551615ul>, (anonymous namespace)::KeyConverter const&)::'lambda'(std::span<char const, 18446744073709551615ul>&, bool)::operator()(std::span<char const, 18446744073709551615ul>&, bool) const
Line
Count
Source
1880
27
    const auto parse_multi_exp = [&](std::span<const char>& in, const bool is_multi_a) -> bool {
1881
27
        const auto max_keys{is_multi_a ? MAX_PUBKEYS_PER_MULTI_A : MAX_PUBKEYS_PER_MULTISIG};
1882
27
        const auto required_ctx{is_multi_a ? MiniscriptContext::TAPSCRIPT : MiniscriptContext::P2WSH};
1883
27
        if (ctx.MsContext() != required_ctx) return false;
1884
        // Get threshold
1885
16
        int next_comma = FindNextChar(in, ',');
1886
16
        if (next_comma < 1) return false;
1887
16
        const auto k_to_integral{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
1888
16
        if (!k_to_integral.has_value()) return false;
1889
15
        const int64_t k{k_to_integral.value()};
1890
15
        in = in.subspan(next_comma + 1);
1891
        // Get keys. It is compatible for both compressed and x-only keys.
1892
15
        std::vector<Key> keys;
1893
64
        while (next_comma != -1) {
1894
49
            next_comma = FindNextChar(in, ',');
1895
49
            int key_length = (next_comma == -1) ? FindNextChar(in, ')') : next_comma;
1896
49
            if (key_length < 1) return false;
1897
49
            std::span<const char> sp{in.begin(), in.begin() + key_length};
1898
49
            auto key = ctx.FromString(sp);
1899
49
            if (!key) return false;
1900
49
            keys.push_back(std::move(*key));
1901
49
            in = in.subspan(key_length + 1);
1902
49
        }
1903
15
        if (keys.size() < 1 || keys.size() > max_keys) return false;
1904
15
        if (k < 1 || k > (int64_t)keys.size()) return false;
1905
15
        if (is_multi_a) {
1906
            // (push + xonly-key + CHECKSIG[ADD]) * n + k + OP_NUMEQUAL(VERIFY), minus one.
1907
2
            script_size += (1 + 32 + 1) * keys.size() + BuildScript(k).size();
1908
2
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), k);
1909
13
        } else {
1910
13
            script_size += 2 + (keys.size() > 16) + (k > 16) + 34 * keys.size();
1911
13
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), k);
1912
13
        }
1913
15
        return true;
1914
15
    };
descriptor.cpp:std::optional<miniscript::Node<unsigned int>> miniscript::internal::Parse<unsigned int, (anonymous namespace)::KeyParser>(std::span<char const, 18446744073709551615ul>, (anonymous namespace)::KeyParser const&)::'lambda'(std::span<char const, 18446744073709551615ul>&, bool)::operator()(std::span<char const, 18446744073709551615ul>&, bool) const
Line
Count
Source
1880
32
    const auto parse_multi_exp = [&](std::span<const char>& in, const bool is_multi_a) -> bool {
1881
32
        const auto max_keys{is_multi_a ? MAX_PUBKEYS_PER_MULTI_A : MAX_PUBKEYS_PER_MULTISIG};
1882
32
        const auto required_ctx{is_multi_a ? MiniscriptContext::TAPSCRIPT : MiniscriptContext::P2WSH};
1883
32
        if (ctx.MsContext() != required_ctx) return false;
1884
        // Get threshold
1885
31
        int next_comma = FindNextChar(in, ',');
1886
31
        if (next_comma < 1) return false;
1887
31
        const auto k_to_integral{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
1888
31
        if (!k_to_integral.has_value()) return false;
1889
31
        const int64_t k{k_to_integral.value()};
1890
31
        in = in.subspan(next_comma + 1);
1891
        // Get keys. It is compatible for both compressed and x-only keys.
1892
31
        std::vector<Key> keys;
1893
111
        while (next_comma != -1) {
1894
80
            next_comma = FindNextChar(in, ',');
1895
80
            int key_length = (next_comma == -1) ? FindNextChar(in, ')') : next_comma;
1896
80
            if (key_length < 1) return false;
1897
80
            std::span<const char> sp{in.begin(), in.begin() + key_length};
1898
80
            auto key = ctx.FromString(sp);
1899
80
            if (!key) return false;
1900
80
            keys.push_back(std::move(*key));
1901
80
            in = in.subspan(key_length + 1);
1902
80
        }
1903
31
        if (keys.size() < 1 || keys.size() > max_keys) return false;
1904
31
        if (k < 1 || k > (int64_t)keys.size()) return false;
1905
31
        if (is_multi_a) {
1906
            // (push + xonly-key + CHECKSIG[ADD]) * n + k + OP_NUMEQUAL(VERIFY), minus one.
1907
14
            script_size += (1 + 32 + 1) * keys.size() + BuildScript(k).size();
1908
14
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), k);
1909
17
        } else {
1910
17
            script_size += 2 + (keys.size() > 16) + (k > 16) + 34 * keys.size();
1911
17
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), k);
1912
17
        }
1913
31
        return true;
1914
31
    };
1915
1916
379k
    while (!to_parse.empty()) {
1917
379k
        if (script_size > max_size) return {};
1918
1919
        // Get the current context we are decoding within
1920
379k
        auto [cur_context, n, k] = to_parse.back();
1921
379k
        to_parse.pop_back();
1922
1923
379k
        switch (cur_context) {
1924
14.1k
        case ParseContext::WRAPPED_EXPR: {
1925
14.1k
            std::optional<size_t> colon_index{};
1926
698k
            for (size_t i = 1; i < in.size(); ++i) {
1927
698k
                if (in[i] == ':') {
1928
6.74k
                    colon_index = i;
1929
6.74k
                    break;
1930
6.74k
                }
1931
691k
                if (in[i] < 'a' || in[i] > 'z') break;
1932
691k
            }
1933
            // If there is no colon, this loop won't execute
1934
14.1k
            bool last_was_v{false};
1935
679k
            for (size_t j = 0; colon_index && j < *colon_index; ++j) {
1936
665k
                if (script_size > max_size) return {};
1937
665k
                if (in[j] == 'a') {
1938
6.28k
                    script_size += 2;
1939
6.28k
                    to_parse.emplace_back(ParseContext::ALT, -1, -1);
1940
659k
                } else if (in[j] == 's') {
1941
75
                    script_size += 1;
1942
75
                    to_parse.emplace_back(ParseContext::SWAP, -1, -1);
1943
659k
                } else if (in[j] == 'c') {
1944
72
                    script_size += 1;
1945
72
                    to_parse.emplace_back(ParseContext::CHECK, -1, -1);
1946
659k
                } else if (in[j] == 'd') {
1947
18
                    script_size += 3;
1948
18
                    to_parse.emplace_back(ParseContext::DUP_IF, -1, -1);
1949
659k
                } else if (in[j] == 'j') {
1950
10
                    script_size += 4;
1951
10
                    to_parse.emplace_back(ParseContext::NON_ZERO, -1, -1);
1952
659k
                } else if (in[j] == 'n') {
1953
658k
                    script_size += 1;
1954
658k
                    to_parse.emplace_back(ParseContext::ZERO_NOTEQUAL, -1, -1);
1955
658k
                } else if (in[j] == 'v') {
1956
                    // do not permit "...vv...:"; it's not valid, and also doesn't trigger early
1957
                    // failure as script_size isn't incremented.
1958
261
                    if (last_was_v) return {};
1959
261
                    to_parse.emplace_back(ParseContext::VERIFY, -1, -1);
1960
261
                } else if (in[j] == 'u') {
1961
23
                    script_size += 4;
1962
23
                    to_parse.emplace_back(ParseContext::WRAP_U, -1, -1);
1963
105
                } else if (in[j] == 't') {
1964
46
                    script_size += 1;
1965
46
                    to_parse.emplace_back(ParseContext::WRAP_T, -1, -1);
1966
59
                } else if (in[j] == 'l') {
1967
                    // The l: wrapper is equivalent to or_i(0,X)
1968
59
                    script_size += 4;
1969
59
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
1970
59
                    to_parse.emplace_back(ParseContext::OR_I, -1, -1);
1971
59
                } else {
1972
0
                    return {};
1973
0
                }
1974
665k
                last_was_v = (in[j] == 'v');
1975
665k
            }
1976
14.1k
            to_parse.emplace_back(ParseContext::EXPR, -1, -1);
1977
14.1k
            if (colon_index) in = in.subspan(*colon_index + 1);
1978
14.1k
            break;
1979
14.1k
        }
1980
14.1k
        case ParseContext::EXPR: {
1981
14.1k
            if (Const("0", in)) {
1982
59
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
1983
14.1k
            } else if (Const("1", in)) {
1984
115
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1);
1985
14.0k
            } else if (Const("pk(", in, /*skip=*/false)) {
1986
972
                std::optional<Key> key = ParseKey<Key, Ctx>("pk", in, ctx);
1987
972
                if (!key) return {};
1988
970
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(Node<Key>(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_K, Vector(std::move(*key)))));
1989
970
                script_size += IsTapscript(ctx.MsContext()) ? 33 : 34;
1990
13.0k
            } else if (Const("pkh(", in, /*skip=*/false)) {
1991
85
                std::optional<Key> key = ParseKey<Key, Ctx>("pkh", in, ctx);
1992
85
                if (!key) return {};
1993
85
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(Node<Key>(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_H, Vector(std::move(*key)))));
1994
85
                script_size += 24;
1995
12.9k
            } else if (Const("pk_k(", in, /*skip=*/false)) {
1996
76
                std::optional<Key> key = ParseKey<Key, Ctx>("pk_k", in, ctx);
1997
76
                if (!key) return {};
1998
74
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_K, Vector(std::move(*key)));
1999
74
                script_size += IsTapscript(ctx.MsContext()) ? 32 : 33;
2000
12.8k
            } else if (Const("pk_h(", in, /*skip=*/false)) {
2001
28
                std::optional<Key> key = ParseKey<Key, Ctx>("pk_h", in, ctx);
2002
28
                if (!key) return {};
2003
28
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_H, Vector(std::move(*key)));
2004
28
                script_size += 23;
2005
12.8k
            } else if (Const("sha256(", in, /*skip=*/false)) {
2006
30
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("sha256", in, 32, ctx);
2007
30
                if (!hash) return {};
2008
30
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, std::move(*hash));
2009
30
                script_size += 38;
2010
12.8k
            } else if (Const("ripemd160(", in, /*skip=*/false)) {
2011
15
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("ripemd160", in, 20, ctx);
2012
15
                if (!hash) return {};
2013
15
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::RIPEMD160, std::move(*hash));
2014
15
                script_size += 26;
2015
12.8k
            } else if (Const("hash256(", in, /*skip=*/false)) {
2016
22
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("hash256", in, 32, ctx);
2017
22
                if (!hash) return {};
2018
22
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, std::move(*hash));
2019
22
                script_size += 38;
2020
12.7k
            } else if (Const("hash160(", in, /*skip=*/false)) {
2021
22
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("hash160", in, 20, ctx);
2022
22
                if (!hash) return {};
2023
22
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, std::move(*hash));
2024
22
                script_size += 26;
2025
12.7k
            } else if (Const("after(", in, /*skip=*/false)) {
2026
128
                auto expr = Expr(in);
2027
128
                if (!Func("after", expr)) return {};
2028
128
                const auto num{ToIntegral<int64_t>(std::string_view(expr.begin(), expr.end()))};
2029
128
                if (!num.has_value() || *num < 1 || *num >= 0x80000000L) return {};
2030
122
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num);
2031
122
                script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
2032
12.6k
            } else if (Const("older(", in, /*skip=*/false)) {
2033
5.55k
                auto expr = Expr(in);
2034
5.55k
                if (!Func("older", expr)) return {};
2035
5.55k
                const auto num{ToIntegral<int64_t>(std::string_view(expr.begin(), expr.end()))};
2036
5.55k
                if (!num.has_value() || *num < 1 || *num >= 0x80000000L) return {};
2037
5.55k
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num);
2038
5.55k
                script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
2039
7.07k
            } else if (Const("multi(", in)) {
2040
41
                if (!parse_multi_exp(in, /* is_multi_a = */false)) return {};
2041
7.03k
            } else if (Const("multi_a(", in)) {
2042
18
                if (!parse_multi_exp(in, /* is_multi_a = */true)) return {};
2043
7.02k
            } else if (Const("thresh(", in)) {
2044
58
                int next_comma = FindNextChar(in, ',');
2045
58
                if (next_comma < 1) return {};
2046
58
                const auto k{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
2047
58
                if (!k.has_value() || *k < 1) return {};
2048
55
                in = in.subspan(next_comma + 1);
2049
                // n = 1 here because we read the first WRAPPED_EXPR before reaching THRESH
2050
55
                to_parse.emplace_back(ParseContext::THRESH, 1, *k);
2051
55
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2052
55
                script_size += 2 + (*k > 16) + (*k > 0x7f) + (*k > 0x7fff) + (*k > 0x7fffff);
2053
6.96k
            } else if (Const("andor(", in)) {
2054
55
                to_parse.emplace_back(ParseContext::ANDOR, -1, -1);
2055
55
                to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
2056
55
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2057
55
                to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2058
55
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2059
55
                to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2060
55
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2061
55
                script_size += 5;
2062
6.90k
            } else {
2063
6.90k
                if (Const("and_n(", in)) {
2064
16
                    to_parse.emplace_back(ParseContext::AND_N, -1, -1);
2065
16
                    script_size += 5;
2066
6.89k
                } else if (Const("and_b(", in)) {
2067
6.19k
                    to_parse.emplace_back(ParseContext::AND_B, -1, -1);
2068
6.19k
                    script_size += 2;
2069
6.19k
                } else if (Const("and_v(", in)) {
2070
185
                    to_parse.emplace_back(ParseContext::AND_V, -1, -1);
2071
185
                    script_size += 1;
2072
512
                } else if (Const("or_b(", in)) {
2073
48
                    to_parse.emplace_back(ParseContext::OR_B, -1, -1);
2074
48
                    script_size += 2;
2075
464
                } else if (Const("or_c(", in)) {
2076
28
                    to_parse.emplace_back(ParseContext::OR_C, -1, -1);
2077
28
                    script_size += 3;
2078
436
                } else if (Const("or_d(", in)) {
2079
42
                    to_parse.emplace_back(ParseContext::OR_D, -1, -1);
2080
42
                    script_size += 4;
2081
394
                } else if (Const("or_i(", in)) {
2082
45
                    to_parse.emplace_back(ParseContext::OR_I, -1, -1);
2083
45
                    script_size += 4;
2084
349
                } else {
2085
349
                    return {};
2086
349
                }
2087
6.55k
                to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
2088
6.55k
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2089
6.55k
                to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2090
6.55k
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2091
6.55k
            }
2092
13.8k
            break;
2093
14.1k
        }
2094
13.8k
        case ParseContext::ALT: {
2095
4.56k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A, Vector(std::move(constructed.back()))};
2096
4.56k
            break;
2097
14.1k
        }
2098
75
        case ParseContext::SWAP: {
2099
75
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S, Vector(std::move(constructed.back()))};
2100
75
            break;
2101
14.1k
        }
2102
68
        case ParseContext::CHECK: {
2103
68
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(std::move(constructed.back()))};
2104
68
            break;
2105
14.1k
        }
2106
18
        case ParseContext::DUP_IF: {
2107
18
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D, Vector(std::move(constructed.back()))};
2108
18
            break;
2109
14.1k
        }
2110
8
        case ParseContext::NON_ZERO: {
2111
8
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J, Vector(std::move(constructed.back()))};
2112
8
            break;
2113
14.1k
        }
2114
329k
        case ParseContext::ZERO_NOTEQUAL: {
2115
329k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N, Vector(std::move(constructed.back()))};
2116
329k
            break;
2117
14.1k
        }
2118
255
        case ParseContext::VERIFY: {
2119
255
            script_size += (constructed.back().GetType() << "x"_mst);
2120
255
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V, Vector(std::move(constructed.back()))};
2121
255
            break;
2122
14.1k
        }
2123
16
        case ParseContext::WRAP_U: {
2124
16
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::OR_I, Vector(std::move(constructed.back()), Node<Key>{internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0})};
2125
16
            break;
2126
14.1k
        }
2127
45
        case ParseContext::WRAP_T: {
2128
45
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::AND_V, Vector(std::move(constructed.back()), Node<Key>{internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1})};
2129
45
            break;
2130
14.1k
        }
2131
4.46k
        case ParseContext::AND_B: {
2132
4.46k
            BuildBack(ctx.MsContext(), Fragment::AND_B, constructed);
2133
4.46k
            break;
2134
14.1k
        }
2135
16
        case ParseContext::AND_N: {
2136
16
            auto mid = std::move(constructed.back());
2137
16
            constructed.pop_back();
2138
16
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR, Vector(std::move(constructed.back()), std::move(mid), Node<Key>{internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0})};
2139
16
            break;
2140
14.1k
        }
2141
176
        case ParseContext::AND_V: {
2142
176
            BuildBack(ctx.MsContext(), Fragment::AND_V, constructed);
2143
176
            break;
2144
14.1k
        }
2145
47
        case ParseContext::OR_B: {
2146
47
            BuildBack(ctx.MsContext(), Fragment::OR_B, constructed);
2147
47
            break;
2148
14.1k
        }
2149
26
        case ParseContext::OR_C: {
2150
26
            BuildBack(ctx.MsContext(), Fragment::OR_C, constructed);
2151
26
            break;
2152
14.1k
        }
2153
41
        case ParseContext::OR_D: {
2154
41
            BuildBack(ctx.MsContext(), Fragment::OR_D, constructed);
2155
41
            break;
2156
14.1k
        }
2157
99
        case ParseContext::OR_I: {
2158
99
            BuildBack(ctx.MsContext(), Fragment::OR_I, constructed);
2159
99
            break;
2160
14.1k
        }
2161
52
        case ParseContext::ANDOR: {
2162
52
            auto right = std::move(constructed.back());
2163
52
            constructed.pop_back();
2164
52
            auto mid = std::move(constructed.back());
2165
52
            constructed.pop_back();
2166
52
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR, Vector(std::move(constructed.back()), std::move(mid), std::move(right))};
2167
52
            break;
2168
14.1k
        }
2169
164
        case ParseContext::THRESH: {
2170
164
            if (in.size() < 1) return {};
2171
164
            if (in[0] == ',') {
2172
110
                in = in.subspan(1);
2173
110
                to_parse.emplace_back(ParseContext::THRESH, n+1, k);
2174
110
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2175
110
                script_size += 2;
2176
110
            } else if (in[0] == ')') {
2177
54
                if (k > n) return {};
2178
52
                in = in.subspan(1);
2179
                // Children are constructed in reverse order, so iterate from end to beginning
2180
52
                std::vector<Node<Key>> subs;
2181
212
                for (int i = 0; i < n; ++i) {
2182
160
                    subs.push_back(std::move(constructed.back()));
2183
160
                    constructed.pop_back();
2184
160
                }
2185
52
                std::reverse(subs.begin(), subs.end());
2186
52
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs), k);
2187
52
            } else {
2188
0
                return {};
2189
0
            }
2190
162
            break;
2191
164
        }
2192
6.65k
        case ParseContext::COMMA: {
2193
6.65k
            if (in.size() < 1 || in[0] != ',') return {};
2194
6.65k
            in = in.subspan(1);
2195
6.65k
            break;
2196
6.65k
        }
2197
4.87k
        case ParseContext::CLOSE_BRACKET: {
2198
4.87k
            if (in.size() < 1 || in[0] != ')') return {};
2199
4.87k
            in = in.subspan(1);
2200
4.87k
            break;
2201
4.87k
        }
2202
379k
        }
2203
379k
    }
2204
2205
    // Sanity checks on the produced miniscript
2206
760
    assert(constructed.size() >= 1);
2207
373
    CHECK_NONFATAL(constructed.size() == 1);
2208
373
    assert(constructed[0].ScriptSize() == script_size);
2209
373
    if (in.size() > 0) return {};
2210
370
    Node<Key> tl_node{std::move(constructed.front())};
2211
370
    tl_node.DuplicateKeyCheck(ctx);
2212
370
    return tl_node;
2213
373
}
miniscript_tests.cpp:std::optional<miniscript::Node<CPubKey>> miniscript::internal::Parse<CPubKey, (anonymous namespace)::KeyConverter>(std::span<char const, 18446744073709551615ul>, (anonymous namespace)::KeyConverter const&)
Line
Count
Source
1857
220
{
1858
220
    using namespace script;
1859
1860
    // Account for the minimum script size for all parsed fragments so far. It "borrows" 1
1861
    // script byte from all leaf nodes, counting it instead whenever a space for a recursive
1862
    // expression is added (through andor, and_*, or_*, thresh). This guarantees that all fragments
1863
    // increment the script_size by at least one, except for:
1864
    // - "0", "1": these leafs are only a single byte, so their subtracted-from increment is 0.
1865
    //   This is not an issue however, as "space" for them has to be created by combinators,
1866
    //   which do increment script_size.
1867
    // - "v:": the v wrapper adds nothing as in some cases it results in no opcode being added
1868
    //   (instead transforming another opcode into its VERIFY form). However, the v: wrapper has
1869
    //   to be interleaved with other fragments to be valid, so this is not a concern.
1870
220
    size_t script_size{1};
1871
220
    size_t max_size{internal::MaxScriptSize(ctx.MsContext())};
1872
1873
    // The two integers are used to hold state for thresh()
1874
220
    std::vector<std::tuple<ParseContext, int64_t, int64_t>> to_parse;
1875
220
    std::vector<Node<Key>> constructed;
1876
1877
220
    to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
1878
1879
    // Parses a multi() or multi_a() from its string representation. Returns false on parsing error.
1880
220
    const auto parse_multi_exp = [&](std::span<const char>& in, const bool is_multi_a) -> bool {
1881
220
        const auto max_keys{is_multi_a ? MAX_PUBKEYS_PER_MULTI_A : MAX_PUBKEYS_PER_MULTISIG};
1882
220
        const auto required_ctx{is_multi_a ? MiniscriptContext::TAPSCRIPT : MiniscriptContext::P2WSH};
1883
220
        if (ctx.MsContext() != required_ctx) return false;
1884
        // Get threshold
1885
220
        int next_comma = FindNextChar(in, ',');
1886
220
        if (next_comma < 1) return false;
1887
220
        const auto k_to_integral{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
1888
220
        if (!k_to_integral.has_value()) return false;
1889
220
        const int64_t k{k_to_integral.value()};
1890
220
        in = in.subspan(next_comma + 1);
1891
        // Get keys. It is compatible for both compressed and x-only keys.
1892
220
        std::vector<Key> keys;
1893
220
        while (next_comma != -1) {
1894
220
            next_comma = FindNextChar(in, ',');
1895
220
            int key_length = (next_comma == -1) ? FindNextChar(in, ')') : next_comma;
1896
220
            if (key_length < 1) return false;
1897
220
            std::span<const char> sp{in.begin(), in.begin() + key_length};
1898
220
            auto key = ctx.FromString(sp);
1899
220
            if (!key) return false;
1900
220
            keys.push_back(std::move(*key));
1901
220
            in = in.subspan(key_length + 1);
1902
220
        }
1903
220
        if (keys.size() < 1 || keys.size() > max_keys) return false;
1904
220
        if (k < 1 || k > (int64_t)keys.size()) return false;
1905
220
        if (is_multi_a) {
1906
            // (push + xonly-key + CHECKSIG[ADD]) * n + k + OP_NUMEQUAL(VERIFY), minus one.
1907
220
            script_size += (1 + 32 + 1) * keys.size() + BuildScript(k).size();
1908
220
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), k);
1909
220
        } else {
1910
220
            script_size += 2 + (keys.size() > 16) + (k > 16) + 34 * keys.size();
1911
220
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), k);
1912
220
        }
1913
220
        return true;
1914
220
    };
1915
1916
46.4k
    while (!to_parse.empty()) {
1917
46.2k
        if (script_size > max_size) return {};
1918
1919
        // Get the current context we are decoding within
1920
46.2k
        auto [cur_context, n, k] = to_parse.back();
1921
46.2k
        to_parse.pop_back();
1922
1923
46.2k
        switch (cur_context) {
1924
12.9k
        case ParseContext::WRAPPED_EXPR: {
1925
12.9k
            std::optional<size_t> colon_index{};
1926
36.2k
            for (size_t i = 1; i < in.size(); ++i) {
1927
36.2k
                if (in[i] == ':') {
1928
6.42k
                    colon_index = i;
1929
6.42k
                    break;
1930
6.42k
                }
1931
29.8k
                if (in[i] < 'a' || in[i] > 'z') break;
1932
29.8k
            }
1933
            // If there is no colon, this loop won't execute
1934
12.9k
            bool last_was_v{false};
1935
19.4k
            for (size_t j = 0; colon_index && j < *colon_index; ++j) {
1936
6.52k
                if (script_size > max_size) return {};
1937
6.52k
                if (in[j] == 'a') {
1938
6.20k
                    script_size += 2;
1939
6.20k
                    to_parse.emplace_back(ParseContext::ALT, -1, -1);
1940
6.20k
                } else if (in[j] == 's') {
1941
21
                    script_size += 1;
1942
21
                    to_parse.emplace_back(ParseContext::SWAP, -1, -1);
1943
303
                } else if (in[j] == 'c') {
1944
56
                    script_size += 1;
1945
56
                    to_parse.emplace_back(ParseContext::CHECK, -1, -1);
1946
247
                } else if (in[j] == 'd') {
1947
8
                    script_size += 3;
1948
8
                    to_parse.emplace_back(ParseContext::DUP_IF, -1, -1);
1949
239
                } else if (in[j] == 'j') {
1950
10
                    script_size += 4;
1951
10
                    to_parse.emplace_back(ParseContext::NON_ZERO, -1, -1);
1952
229
                } else if (in[j] == 'n') {
1953
16
                    script_size += 1;
1954
16
                    to_parse.emplace_back(ParseContext::ZERO_NOTEQUAL, -1, -1);
1955
213
                } else if (in[j] == 'v') {
1956
                    // do not permit "...vv...:"; it's not valid, and also doesn't trigger early
1957
                    // failure as script_size isn't incremented.
1958
103
                    if (last_was_v) return {};
1959
103
                    to_parse.emplace_back(ParseContext::VERIFY, -1, -1);
1960
110
                } else if (in[j] == 'u') {
1961
23
                    script_size += 4;
1962
23
                    to_parse.emplace_back(ParseContext::WRAP_U, -1, -1);
1963
87
                } else if (in[j] == 't') {
1964
44
                    script_size += 1;
1965
44
                    to_parse.emplace_back(ParseContext::WRAP_T, -1, -1);
1966
44
                } else if (in[j] == 'l') {
1967
                    // The l: wrapper is equivalent to or_i(0,X)
1968
43
                    script_size += 4;
1969
43
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
1970
43
                    to_parse.emplace_back(ParseContext::OR_I, -1, -1);
1971
43
                } else {
1972
0
                    return {};
1973
0
                }
1974
6.52k
                last_was_v = (in[j] == 'v');
1975
6.52k
            }
1976
12.9k
            to_parse.emplace_back(ParseContext::EXPR, -1, -1);
1977
12.9k
            if (colon_index) in = in.subspan(*colon_index + 1);
1978
12.9k
            break;
1979
12.9k
        }
1980
12.9k
        case ParseContext::EXPR: {
1981
12.9k
            if (Const("0", in)) {
1982
56
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
1983
12.9k
            } else if (Const("1", in)) {
1984
112
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1);
1985
12.7k
            } else if (Const("pk(", in, /*skip=*/false)) {
1986
715
                std::optional<Key> key = ParseKey<Key, Ctx>("pk", in, ctx);
1987
715
                if (!key) return {};
1988
715
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(Node<Key>(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_K, Vector(std::move(*key)))));
1989
715
                script_size += IsTapscript(ctx.MsContext()) ? 33 : 34;
1990
12.0k
            } else if (Const("pkh(", in, /*skip=*/false)) {
1991
3
                std::optional<Key> key = ParseKey<Key, Ctx>("pkh", in, ctx);
1992
3
                if (!key) return {};
1993
3
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(Node<Key>(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_H, Vector(std::move(*key)))));
1994
3
                script_size += 24;
1995
12.0k
            } else if (Const("pk_k(", in, /*skip=*/false)) {
1996
51
                std::optional<Key> key = ParseKey<Key, Ctx>("pk_k", in, ctx);
1997
51
                if (!key) return {};
1998
51
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_K, Vector(std::move(*key)));
1999
51
                script_size += IsTapscript(ctx.MsContext()) ? 32 : 33;
2000
12.0k
            } else if (Const("pk_h(", in, /*skip=*/false)) {
2001
25
                std::optional<Key> key = ParseKey<Key, Ctx>("pk_h", in, ctx);
2002
25
                if (!key) return {};
2003
25
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_H, Vector(std::move(*key)));
2004
25
                script_size += 23;
2005
11.9k
            } else if (Const("sha256(", in, /*skip=*/false)) {
2006
22
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("sha256", in, 32, ctx);
2007
22
                if (!hash) return {};
2008
22
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, std::move(*hash));
2009
22
                script_size += 38;
2010
11.9k
            } else if (Const("ripemd160(", in, /*skip=*/false)) {
2011
7
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("ripemd160", in, 20, ctx);
2012
7
                if (!hash) return {};
2013
7
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::RIPEMD160, std::move(*hash));
2014
7
                script_size += 26;
2015
11.9k
            } else if (Const("hash256(", in, /*skip=*/false)) {
2016
14
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("hash256", in, 32, ctx);
2017
14
                if (!hash) return {};
2018
14
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, std::move(*hash));
2019
14
                script_size += 38;
2020
11.9k
            } else if (Const("hash160(", in, /*skip=*/false)) {
2021
6
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("hash160", in, 20, ctx);
2022
6
                if (!hash) return {};
2023
6
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, std::move(*hash));
2024
6
                script_size += 26;
2025
11.9k
            } else if (Const("after(", in, /*skip=*/false)) {
2026
79
                auto expr = Expr(in);
2027
79
                if (!Func("after", expr)) return {};
2028
79
                const auto num{ToIntegral<int64_t>(std::string_view(expr.begin(), expr.end()))};
2029
79
                if (!num.has_value() || *num < 1 || *num >= 0x80000000L) return {};
2030
73
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num);
2031
73
                script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
2032
11.8k
            } else if (Const("older(", in, /*skip=*/false)) {
2033
5.48k
                auto expr = Expr(in);
2034
5.48k
                if (!Func("older", expr)) return {};
2035
5.48k
                const auto num{ToIntegral<int64_t>(std::string_view(expr.begin(), expr.end()))};
2036
5.48k
                if (!num.has_value() || *num < 1 || *num >= 0x80000000L) return {};
2037
5.47k
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num);
2038
5.47k
                script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
2039
6.38k
            } else if (Const("multi(", in)) {
2040
23
                if (!parse_multi_exp(in, /* is_multi_a = */false)) return {};
2041
6.36k
            } else if (Const("multi_a(", in)) {
2042
4
                if (!parse_multi_exp(in, /* is_multi_a = */true)) return {};
2043
6.35k
            } else if (Const("thresh(", in)) {
2044
25
                int next_comma = FindNextChar(in, ',');
2045
25
                if (next_comma < 1) return {};
2046
25
                const auto k{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
2047
25
                if (!k.has_value() || *k < 1) return {};
2048
22
                in = in.subspan(next_comma + 1);
2049
                // n = 1 here because we read the first WRAPPED_EXPR before reaching THRESH
2050
22
                to_parse.emplace_back(ParseContext::THRESH, 1, *k);
2051
22
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2052
22
                script_size += 2 + (*k > 16) + (*k > 0x7f) + (*k > 0x7fff) + (*k > 0x7fffff);
2053
6.33k
            } else if (Const("andor(", in)) {
2054
30
                to_parse.emplace_back(ParseContext::ANDOR, -1, -1);
2055
30
                to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
2056
30
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2057
30
                to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2058
30
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2059
30
                to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2060
30
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2061
30
                script_size += 5;
2062
6.30k
            } else {
2063
6.30k
                if (Const("and_n(", in)) {
2064
8
                    to_parse.emplace_back(ParseContext::AND_N, -1, -1);
2065
8
                    script_size += 5;
2066
6.29k
                } else if (Const("and_b(", in)) {
2067
6.15k
                    to_parse.emplace_back(ParseContext::AND_B, -1, -1);
2068
6.15k
                    script_size += 2;
2069
6.15k
                } else if (Const("and_v(", in)) {
2070
43
                    to_parse.emplace_back(ParseContext::AND_V, -1, -1);
2071
43
                    script_size += 1;
2072
97
                } else if (Const("or_b(", in)) {
2073
22
                    to_parse.emplace_back(ParseContext::OR_B, -1, -1);
2074
22
                    script_size += 2;
2075
75
                } else if (Const("or_c(", in)) {
2076
16
                    to_parse.emplace_back(ParseContext::OR_C, -1, -1);
2077
16
                    script_size += 3;
2078
59
                } else if (Const("or_d(", in)) {
2079
24
                    to_parse.emplace_back(ParseContext::OR_D, -1, -1);
2080
24
                    script_size += 4;
2081
35
                } else if (Const("or_i(", in)) {
2082
35
                    to_parse.emplace_back(ParseContext::OR_I, -1, -1);
2083
35
                    script_size += 4;
2084
35
                } else {
2085
0
                    return {};
2086
0
                }
2087
6.30k
                to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
2088
6.30k
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2089
6.30k
                to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2090
6.30k
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2091
6.30k
            }
2092
12.9k
            break;
2093
12.9k
        }
2094
12.9k
        case ParseContext::ALT: {
2095
4.48k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A, Vector(std::move(constructed.back()))};
2096
4.48k
            break;
2097
12.9k
        }
2098
21
        case ParseContext::SWAP: {
2099
21
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S, Vector(std::move(constructed.back()))};
2100
21
            break;
2101
12.9k
        }
2102
54
        case ParseContext::CHECK: {
2103
54
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(std::move(constructed.back()))};
2104
54
            break;
2105
12.9k
        }
2106
8
        case ParseContext::DUP_IF: {
2107
8
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D, Vector(std::move(constructed.back()))};
2108
8
            break;
2109
12.9k
        }
2110
8
        case ParseContext::NON_ZERO: {
2111
8
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J, Vector(std::move(constructed.back()))};
2112
8
            break;
2113
12.9k
        }
2114
15
        case ParseContext::ZERO_NOTEQUAL: {
2115
15
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N, Vector(std::move(constructed.back()))};
2116
15
            break;
2117
12.9k
        }
2118
99
        case ParseContext::VERIFY: {
2119
99
            script_size += (constructed.back().GetType() << "x"_mst);
2120
99
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V, Vector(std::move(constructed.back()))};
2121
99
            break;
2122
12.9k
        }
2123
16
        case ParseContext::WRAP_U: {
2124
16
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::OR_I, Vector(std::move(constructed.back()), Node<Key>{internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0})};
2125
16
            break;
2126
12.9k
        }
2127
43
        case ParseContext::WRAP_T: {
2128
43
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::AND_V, Vector(std::move(constructed.back()), Node<Key>{internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1})};
2129
43
            break;
2130
12.9k
        }
2131
4.42k
        case ParseContext::AND_B: {
2132
4.42k
            BuildBack(ctx.MsContext(), Fragment::AND_B, constructed);
2133
4.42k
            break;
2134
12.9k
        }
2135
8
        case ParseContext::AND_N: {
2136
8
            auto mid = std::move(constructed.back());
2137
8
            constructed.pop_back();
2138
8
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR, Vector(std::move(constructed.back()), std::move(mid), Node<Key>{internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0})};
2139
8
            break;
2140
12.9k
        }
2141
38
        case ParseContext::AND_V: {
2142
38
            BuildBack(ctx.MsContext(), Fragment::AND_V, constructed);
2143
38
            break;
2144
12.9k
        }
2145
21
        case ParseContext::OR_B: {
2146
21
            BuildBack(ctx.MsContext(), Fragment::OR_B, constructed);
2147
21
            break;
2148
12.9k
        }
2149
14
        case ParseContext::OR_C: {
2150
14
            BuildBack(ctx.MsContext(), Fragment::OR_C, constructed);
2151
14
            break;
2152
12.9k
        }
2153
23
        case ParseContext::OR_D: {
2154
23
            BuildBack(ctx.MsContext(), Fragment::OR_D, constructed);
2155
23
            break;
2156
12.9k
        }
2157
73
        case ParseContext::OR_I: {
2158
73
            BuildBack(ctx.MsContext(), Fragment::OR_I, constructed);
2159
73
            break;
2160
12.9k
        }
2161
29
        case ParseContext::ANDOR: {
2162
29
            auto right = std::move(constructed.back());
2163
29
            constructed.pop_back();
2164
29
            auto mid = std::move(constructed.back());
2165
29
            constructed.pop_back();
2166
29
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR, Vector(std::move(constructed.back()), std::move(mid), std::move(right))};
2167
29
            break;
2168
12.9k
        }
2169
60
        case ParseContext::THRESH: {
2170
60
            if (in.size() < 1) return {};
2171
60
            if (in[0] == ',') {
2172
39
                in = in.subspan(1);
2173
39
                to_parse.emplace_back(ParseContext::THRESH, n+1, k);
2174
39
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2175
39
                script_size += 2;
2176
39
            } else if (in[0] == ')') {
2177
21
                if (k > n) return {};
2178
19
                in = in.subspan(1);
2179
                // Children are constructed in reverse order, so iterate from end to beginning
2180
19
                std::vector<Node<Key>> subs;
2181
75
                for (int i = 0; i < n; ++i) {
2182
56
                    subs.push_back(std::move(constructed.back()));
2183
56
                    constructed.pop_back();
2184
56
                }
2185
19
                std::reverse(subs.begin(), subs.end());
2186
19
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs), k);
2187
19
            } else {
2188
0
                return {};
2189
0
            }
2190
58
            break;
2191
60
        }
2192
6.34k
        case ParseContext::COMMA: {
2193
6.34k
            if (in.size() < 1 || in[0] != ',') return {};
2194
6.34k
            in = in.subspan(1);
2195
6.34k
            break;
2196
6.34k
        }
2197
4.59k
        case ParseContext::CLOSE_BRACKET: {
2198
4.59k
            if (in.size() < 1 || in[0] != ')') return {};
2199
4.59k
            in = in.subspan(1);
2200
4.59k
            break;
2201
4.59k
        }
2202
46.2k
        }
2203
46.2k
    }
2204
2205
    // Sanity checks on the produced miniscript
2206
220
    assert(constructed.size() >= 1);
2207
188
    CHECK_NONFATAL(constructed.size() == 1);
2208
188
    assert(constructed[0].ScriptSize() == script_size);
2209
188
    if (in.size() > 0) return {};
2210
188
    Node<Key> tl_node{std::move(constructed.front())};
2211
188
    tl_node.DuplicateKeyCheck(ctx);
2212
188
    return tl_node;
2213
188
}
descriptor.cpp:std::optional<miniscript::Node<unsigned int>> miniscript::internal::Parse<unsigned int, (anonymous namespace)::KeyParser>(std::span<char const, 18446744073709551615ul>, (anonymous namespace)::KeyParser const&)
Line
Count
Source
1857
540
{
1858
540
    using namespace script;
1859
1860
    // Account for the minimum script size for all parsed fragments so far. It "borrows" 1
1861
    // script byte from all leaf nodes, counting it instead whenever a space for a recursive
1862
    // expression is added (through andor, and_*, or_*, thresh). This guarantees that all fragments
1863
    // increment the script_size by at least one, except for:
1864
    // - "0", "1": these leafs are only a single byte, so their subtracted-from increment is 0.
1865
    //   This is not an issue however, as "space" for them has to be created by combinators,
1866
    //   which do increment script_size.
1867
    // - "v:": the v wrapper adds nothing as in some cases it results in no opcode being added
1868
    //   (instead transforming another opcode into its VERIFY form). However, the v: wrapper has
1869
    //   to be interleaved with other fragments to be valid, so this is not a concern.
1870
540
    size_t script_size{1};
1871
540
    size_t max_size{internal::MaxScriptSize(ctx.MsContext())};
1872
1873
    // The two integers are used to hold state for thresh()
1874
540
    std::vector<std::tuple<ParseContext, int64_t, int64_t>> to_parse;
1875
540
    std::vector<Node<Key>> constructed;
1876
1877
540
    to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
1878
1879
    // Parses a multi() or multi_a() from its string representation. Returns false on parsing error.
1880
540
    const auto parse_multi_exp = [&](std::span<const char>& in, const bool is_multi_a) -> bool {
1881
540
        const auto max_keys{is_multi_a ? MAX_PUBKEYS_PER_MULTI_A : MAX_PUBKEYS_PER_MULTISIG};
1882
540
        const auto required_ctx{is_multi_a ? MiniscriptContext::TAPSCRIPT : MiniscriptContext::P2WSH};
1883
540
        if (ctx.MsContext() != required_ctx) return false;
1884
        // Get threshold
1885
540
        int next_comma = FindNextChar(in, ',');
1886
540
        if (next_comma < 1) return false;
1887
540
        const auto k_to_integral{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
1888
540
        if (!k_to_integral.has_value()) return false;
1889
540
        const int64_t k{k_to_integral.value()};
1890
540
        in = in.subspan(next_comma + 1);
1891
        // Get keys. It is compatible for both compressed and x-only keys.
1892
540
        std::vector<Key> keys;
1893
540
        while (next_comma != -1) {
1894
540
            next_comma = FindNextChar(in, ',');
1895
540
            int key_length = (next_comma == -1) ? FindNextChar(in, ')') : next_comma;
1896
540
            if (key_length < 1) return false;
1897
540
            std::span<const char> sp{in.begin(), in.begin() + key_length};
1898
540
            auto key = ctx.FromString(sp);
1899
540
            if (!key) return false;
1900
540
            keys.push_back(std::move(*key));
1901
540
            in = in.subspan(key_length + 1);
1902
540
        }
1903
540
        if (keys.size() < 1 || keys.size() > max_keys) return false;
1904
540
        if (k < 1 || k > (int64_t)keys.size()) return false;
1905
540
        if (is_multi_a) {
1906
            // (push + xonly-key + CHECKSIG[ADD]) * n + k + OP_NUMEQUAL(VERIFY), minus one.
1907
540
            script_size += (1 + 32 + 1) * keys.size() + BuildScript(k).size();
1908
540
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), k);
1909
540
        } else {
1910
540
            script_size += 2 + (keys.size() > 16) + (k > 16) + 34 * keys.size();
1911
540
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), k);
1912
540
        }
1913
540
        return true;
1914
540
    };
1915
1916
333k
    while (!to_parse.empty()) {
1917
333k
        if (script_size > max_size) return {};
1918
1919
        // Get the current context we are decoding within
1920
333k
        auto [cur_context, n, k] = to_parse.back();
1921
333k
        to_parse.pop_back();
1922
1923
333k
        switch (cur_context) {
1924
1.23k
        case ParseContext::WRAPPED_EXPR: {
1925
1.23k
            std::optional<size_t> colon_index{};
1926
662k
            for (size_t i = 1; i < in.size(); ++i) {
1927
662k
                if (in[i] == ':') {
1928
313
                    colon_index = i;
1929
313
                    break;
1930
313
                }
1931
662k
                if (in[i] < 'a' || in[i] > 'z') break;
1932
662k
            }
1933
            // If there is no colon, this loop won't execute
1934
1.23k
            bool last_was_v{false};
1935
660k
            for (size_t j = 0; colon_index && j < *colon_index; ++j) {
1936
659k
                if (script_size > max_size) return {};
1937
659k
                if (in[j] == 'a') {
1938
82
                    script_size += 2;
1939
82
                    to_parse.emplace_back(ParseContext::ALT, -1, -1);
1940
659k
                } else if (in[j] == 's') {
1941
54
                    script_size += 1;
1942
54
                    to_parse.emplace_back(ParseContext::SWAP, -1, -1);
1943
659k
                } else if (in[j] == 'c') {
1944
16
                    script_size += 1;
1945
16
                    to_parse.emplace_back(ParseContext::CHECK, -1, -1);
1946
659k
                } else if (in[j] == 'd') {
1947
10
                    script_size += 3;
1948
10
                    to_parse.emplace_back(ParseContext::DUP_IF, -1, -1);
1949
659k
                } else if (in[j] == 'j') {
1950
0
                    script_size += 4;
1951
0
                    to_parse.emplace_back(ParseContext::NON_ZERO, -1, -1);
1952
659k
                } else if (in[j] == 'n') {
1953
658k
                    script_size += 1;
1954
658k
                    to_parse.emplace_back(ParseContext::ZERO_NOTEQUAL, -1, -1);
1955
658k
                } else if (in[j] == 'v') {
1956
                    // do not permit "...vv...:"; it's not valid, and also doesn't trigger early
1957
                    // failure as script_size isn't incremented.
1958
158
                    if (last_was_v) return {};
1959
158
                    to_parse.emplace_back(ParseContext::VERIFY, -1, -1);
1960
158
                } else if (in[j] == 'u') {
1961
0
                    script_size += 4;
1962
0
                    to_parse.emplace_back(ParseContext::WRAP_U, -1, -1);
1963
18
                } else if (in[j] == 't') {
1964
2
                    script_size += 1;
1965
2
                    to_parse.emplace_back(ParseContext::WRAP_T, -1, -1);
1966
16
                } else if (in[j] == 'l') {
1967
                    // The l: wrapper is equivalent to or_i(0,X)
1968
16
                    script_size += 4;
1969
16
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
1970
16
                    to_parse.emplace_back(ParseContext::OR_I, -1, -1);
1971
16
                } else {
1972
0
                    return {};
1973
0
                }
1974
659k
                last_was_v = (in[j] == 'v');
1975
659k
            }
1976
1.23k
            to_parse.emplace_back(ParseContext::EXPR, -1, -1);
1977
1.23k
            if (colon_index) in = in.subspan(*colon_index + 1);
1978
1.23k
            break;
1979
1.23k
        }
1980
1.23k
        case ParseContext::EXPR: {
1981
1.23k
            if (Const("0", in)) {
1982
3
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
1983
1.22k
            } else if (Const("1", in)) {
1984
3
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1);
1985
1.22k
            } else if (Const("pk(", in, /*skip=*/false)) {
1986
257
                std::optional<Key> key = ParseKey<Key, Ctx>("pk", in, ctx);
1987
257
                if (!key) return {};
1988
255
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(Node<Key>(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_K, Vector(std::move(*key)))));
1989
255
                script_size += IsTapscript(ctx.MsContext()) ? 33 : 34;
1990
968
            } else if (Const("pkh(", in, /*skip=*/false)) {
1991
82
                std::optional<Key> key = ParseKey<Key, Ctx>("pkh", in, ctx);
1992
82
                if (!key) return {};
1993
82
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(Node<Key>(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_H, Vector(std::move(*key)))));
1994
82
                script_size += 24;
1995
886
            } else if (Const("pk_k(", in, /*skip=*/false)) {
1996
25
                std::optional<Key> key = ParseKey<Key, Ctx>("pk_k", in, ctx);
1997
25
                if (!key) return {};
1998
23
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_K, Vector(std::move(*key)));
1999
23
                script_size += IsTapscript(ctx.MsContext()) ? 32 : 33;
2000
861
            } else if (Const("pk_h(", in, /*skip=*/false)) {
2001
3
                std::optional<Key> key = ParseKey<Key, Ctx>("pk_h", in, ctx);
2002
3
                if (!key) return {};
2003
3
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_H, Vector(std::move(*key)));
2004
3
                script_size += 23;
2005
858
            } else if (Const("sha256(", in, /*skip=*/false)) {
2006
8
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("sha256", in, 32, ctx);
2007
8
                if (!hash) return {};
2008
8
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, std::move(*hash));
2009
8
                script_size += 38;
2010
850
            } else if (Const("ripemd160(", in, /*skip=*/false)) {
2011
8
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("ripemd160", in, 20, ctx);
2012
8
                if (!hash) return {};
2013
8
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::RIPEMD160, std::move(*hash));
2014
8
                script_size += 26;
2015
842
            } else if (Const("hash256(", in, /*skip=*/false)) {
2016
8
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("hash256", in, 32, ctx);
2017
8
                if (!hash) return {};
2018
8
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, std::move(*hash));
2019
8
                script_size += 38;
2020
834
            } else if (Const("hash160(", in, /*skip=*/false)) {
2021
16
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("hash160", in, 20, ctx);
2022
16
                if (!hash) return {};
2023
16
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, std::move(*hash));
2024
16
                script_size += 26;
2025
818
            } else if (Const("after(", in, /*skip=*/false)) {
2026
49
                auto expr = Expr(in);
2027
49
                if (!Func("after", expr)) return {};
2028
49
                const auto num{ToIntegral<int64_t>(std::string_view(expr.begin(), expr.end()))};
2029
49
                if (!num.has_value() || *num < 1 || *num >= 0x80000000L) return {};
2030
49
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num);
2031
49
                script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
2032
769
            } else if (Const("older(", in, /*skip=*/false)) {
2033
73
                auto expr = Expr(in);
2034
73
                if (!Func("older", expr)) return {};
2035
73
                const auto num{ToIntegral<int64_t>(std::string_view(expr.begin(), expr.end()))};
2036
73
                if (!num.has_value() || *num < 1 || *num >= 0x80000000L) return {};
2037
73
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num);
2038
73
                script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
2039
696
            } else if (Const("multi(", in)) {
2040
18
                if (!parse_multi_exp(in, /* is_multi_a = */false)) return {};
2041
678
            } else if (Const("multi_a(", in)) {
2042
14
                if (!parse_multi_exp(in, /* is_multi_a = */true)) return {};
2043
664
            } else if (Const("thresh(", in)) {
2044
33
                int next_comma = FindNextChar(in, ',');
2045
33
                if (next_comma < 1) return {};
2046
33
                const auto k{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
2047
33
                if (!k.has_value() || *k < 1) return {};
2048
33
                in = in.subspan(next_comma + 1);
2049
                // n = 1 here because we read the first WRAPPED_EXPR before reaching THRESH
2050
33
                to_parse.emplace_back(ParseContext::THRESH, 1, *k);
2051
33
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2052
33
                script_size += 2 + (*k > 16) + (*k > 0x7f) + (*k > 0x7fff) + (*k > 0x7fffff);
2053
631
            } else if (Const("andor(", in)) {
2054
25
                to_parse.emplace_back(ParseContext::ANDOR, -1, -1);
2055
25
                to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
2056
25
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2057
25
                to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2058
25
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2059
25
                to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2060
25
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2061
25
                script_size += 5;
2062
606
            } else {
2063
606
                if (Const("and_n(", in)) {
2064
8
                    to_parse.emplace_back(ParseContext::AND_N, -1, -1);
2065
8
                    script_size += 5;
2066
598
                } else if (Const("and_b(", in)) {
2067
41
                    to_parse.emplace_back(ParseContext::AND_B, -1, -1);
2068
41
                    script_size += 2;
2069
557
                } else if (Const("and_v(", in)) {
2070
142
                    to_parse.emplace_back(ParseContext::AND_V, -1, -1);
2071
142
                    script_size += 1;
2072
415
                } else if (Const("or_b(", in)) {
2073
26
                    to_parse.emplace_back(ParseContext::OR_B, -1, -1);
2074
26
                    script_size += 2;
2075
389
                } else if (Const("or_c(", in)) {
2076
12
                    to_parse.emplace_back(ParseContext::OR_C, -1, -1);
2077
12
                    script_size += 3;
2078
377
                } else if (Const("or_d(", in)) {
2079
18
                    to_parse.emplace_back(ParseContext::OR_D, -1, -1);
2080
18
                    script_size += 4;
2081
359
                } else if (Const("or_i(", in)) {
2082
10
                    to_parse.emplace_back(ParseContext::OR_I, -1, -1);
2083
10
                    script_size += 4;
2084
349
                } else {
2085
349
                    return {};
2086
349
                }
2087
257
                to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
2088
257
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2089
257
                to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2090
257
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2091
257
            }
2092
877
            break;
2093
1.23k
        }
2094
877
        case ParseContext::ALT: {
2095
82
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A, Vector(std::move(constructed.back()))};
2096
82
            break;
2097
1.23k
        }
2098
54
        case ParseContext::SWAP: {
2099
54
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S, Vector(std::move(constructed.back()))};
2100
54
            break;
2101
1.23k
        }
2102
14
        case ParseContext::CHECK: {
2103
14
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(std::move(constructed.back()))};
2104
14
            break;
2105
1.23k
        }
2106
10
        case ParseContext::DUP_IF: {
2107
10
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D, Vector(std::move(constructed.back()))};
2108
10
            break;
2109
1.23k
        }
2110
0
        case ParseContext::NON_ZERO: {
2111
0
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J, Vector(std::move(constructed.back()))};
2112
0
            break;
2113
1.23k
        }
2114
329k
        case ParseContext::ZERO_NOTEQUAL: {
2115
329k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N, Vector(std::move(constructed.back()))};
2116
329k
            break;
2117
1.23k
        }
2118
156
        case ParseContext::VERIFY: {
2119
156
            script_size += (constructed.back().GetType() << "x"_mst);
2120
156
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V, Vector(std::move(constructed.back()))};
2121
156
            break;
2122
1.23k
        }
2123
0
        case ParseContext::WRAP_U: {
2124
0
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::OR_I, Vector(std::move(constructed.back()), Node<Key>{internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0})};
2125
0
            break;
2126
1.23k
        }
2127
2
        case ParseContext::WRAP_T: {
2128
2
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::AND_V, Vector(std::move(constructed.back()), Node<Key>{internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1})};
2129
2
            break;
2130
1.23k
        }
2131
41
        case ParseContext::AND_B: {
2132
41
            BuildBack(ctx.MsContext(), Fragment::AND_B, constructed);
2133
41
            break;
2134
1.23k
        }
2135
8
        case ParseContext::AND_N: {
2136
8
            auto mid = std::move(constructed.back());
2137
8
            constructed.pop_back();
2138
8
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR, Vector(std::move(constructed.back()), std::move(mid), Node<Key>{internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0})};
2139
8
            break;
2140
1.23k
        }
2141
138
        case ParseContext::AND_V: {
2142
138
            BuildBack(ctx.MsContext(), Fragment::AND_V, constructed);
2143
138
            break;
2144
1.23k
        }
2145
26
        case ParseContext::OR_B: {
2146
26
            BuildBack(ctx.MsContext(), Fragment::OR_B, constructed);
2147
26
            break;
2148
1.23k
        }
2149
12
        case ParseContext::OR_C: {
2150
12
            BuildBack(ctx.MsContext(), Fragment::OR_C, constructed);
2151
12
            break;
2152
1.23k
        }
2153
18
        case ParseContext::OR_D: {
2154
18
            BuildBack(ctx.MsContext(), Fragment::OR_D, constructed);
2155
18
            break;
2156
1.23k
        }
2157
26
        case ParseContext::OR_I: {
2158
26
            BuildBack(ctx.MsContext(), Fragment::OR_I, constructed);
2159
26
            break;
2160
1.23k
        }
2161
23
        case ParseContext::ANDOR: {
2162
23
            auto right = std::move(constructed.back());
2163
23
            constructed.pop_back();
2164
23
            auto mid = std::move(constructed.back());
2165
23
            constructed.pop_back();
2166
23
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR, Vector(std::move(constructed.back()), std::move(mid), std::move(right))};
2167
23
            break;
2168
1.23k
        }
2169
104
        case ParseContext::THRESH: {
2170
104
            if (in.size() < 1) return {};
2171
104
            if (in[0] == ',') {
2172
71
                in = in.subspan(1);
2173
71
                to_parse.emplace_back(ParseContext::THRESH, n+1, k);
2174
71
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2175
71
                script_size += 2;
2176
71
            } else if (in[0] == ')') {
2177
33
                if (k > n) return {};
2178
33
                in = in.subspan(1);
2179
                // Children are constructed in reverse order, so iterate from end to beginning
2180
33
                std::vector<Node<Key>> subs;
2181
137
                for (int i = 0; i < n; ++i) {
2182
104
                    subs.push_back(std::move(constructed.back()));
2183
104
                    constructed.pop_back();
2184
104
                }
2185
33
                std::reverse(subs.begin(), subs.end());
2186
33
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs), k);
2187
33
            } else {
2188
0
                return {};
2189
0
            }
2190
104
            break;
2191
104
        }
2192
305
        case ParseContext::COMMA: {
2193
305
            if (in.size() < 1 || in[0] != ',') return {};
2194
305
            in = in.subspan(1);
2195
305
            break;
2196
305
        }
2197
276
        case ParseContext::CLOSE_BRACKET: {
2198
276
            if (in.size() < 1 || in[0] != ')') return {};
2199
276
            in = in.subspan(1);
2200
276
            break;
2201
276
        }
2202
333k
        }
2203
333k
    }
2204
2205
    // Sanity checks on the produced miniscript
2206
540
    assert(constructed.size() >= 1);
2207
185
    CHECK_NONFATAL(constructed.size() == 1);
2208
185
    assert(constructed[0].ScriptSize() == script_size);
2209
185
    if (in.size() > 0) return {};
2210
182
    Node<Key> tl_node{std::move(constructed.front())};
2211
182
    tl_node.DuplicateKeyCheck(ctx);
2212
182
    return tl_node;
2213
185
}
2214
2215
/** Decode a script into opcode/push pairs.
2216
 *
2217
 * Construct a vector with one element per opcode in the script, in reverse order.
2218
 * Each element is a pair consisting of the opcode, as well as the data pushed by
2219
 * the opcode (including OP_n), if any. OP_CHECKSIGVERIFY, OP_CHECKMULTISIGVERIFY,
2220
 * OP_NUMEQUALVERIFY and OP_EQUALVERIFY are decomposed into OP_CHECKSIG, OP_CHECKMULTISIG,
2221
 * OP_EQUAL and OP_NUMEQUAL respectively, plus OP_VERIFY.
2222
 */
2223
std::optional<std::vector<Opcode>> DecomposeScript(const CScript& script);
2224
2225
/** Determine whether the passed pair (created by DecomposeScript) is pushing a number. */
2226
std::optional<int64_t> ParseScriptNumber(const Opcode& in);
2227
2228
enum class DecodeContext {
2229
    /** A single expression of type B, K, or V. Specifically, this can't be an
2230
     * and_v or an expression of type W (a: and s: wrappers). */
2231
    SINGLE_BKV_EXPR,
2232
    /** Potentially multiple SINGLE_BKV_EXPRs as children of (potentially multiple)
2233
     * and_v expressions. Syntactic sugar for MAYBE_AND_V + SINGLE_BKV_EXPR. */
2234
    BKV_EXPR,
2235
    /** An expression of type W (a: or s: wrappers). */
2236
    W_EXPR,
2237
2238
    /** SWAP expects the next element to be OP_SWAP (inside a W-type expression that
2239
     * didn't end with FROMALTSTACK), and wraps the top of the constructed stack
2240
     * with s: */
2241
    SWAP,
2242
    /** ALT expects the next element to be TOALTSTACK (we must have already read a
2243
     * FROMALTSTACK earlier), and wraps the top of the constructed stack with a: */
2244
    ALT,
2245
    /** CHECK wraps the top constructed node with c: */
2246
    CHECK,
2247
    /** DUP_IF wraps the top constructed node with d: */
2248
    DUP_IF,
2249
    /** VERIFY wraps the top constructed node with v: */
2250
    VERIFY,
2251
    /** NON_ZERO wraps the top constructed node with j: */
2252
    NON_ZERO,
2253
    /** ZERO_NOTEQUAL wraps the top constructed node with n: */
2254
    ZERO_NOTEQUAL,
2255
2256
    /** MAYBE_AND_V will check if the next part of the script could be a valid
2257
     * miniscript sub-expression, and if so it will push AND_V and SINGLE_BKV_EXPR
2258
     * to decode it and construct the and_v node. This is recursive, to deal with
2259
     * multiple and_v nodes inside each other. */
2260
    MAYBE_AND_V,
2261
    /** AND_V will construct an and_v node from the last two constructed nodes. */
2262
    AND_V,
2263
    /** AND_B will construct an and_b node from the last two constructed nodes. */
2264
    AND_B,
2265
    /** ANDOR will construct an andor node from the last three constructed nodes. */
2266
    ANDOR,
2267
    /** OR_B will construct an or_b node from the last two constructed nodes. */
2268
    OR_B,
2269
    /** OR_C will construct an or_c node from the last two constructed nodes. */
2270
    OR_C,
2271
    /** OR_D will construct an or_d node from the last two constructed nodes. */
2272
    OR_D,
2273
2274
    /** In a thresh expression, all sub-expressions other than the first are W-type,
2275
     * and end in OP_ADD. THRESH_W will check for this OP_ADD and either push a W_EXPR
2276
     * or a SINGLE_BKV_EXPR and jump to THRESH_E accordingly. */
2277
    THRESH_W,
2278
    /** THRESH_E constructs a thresh node from the appropriate number of constructed
2279
     * children. */
2280
    THRESH_E,
2281
2282
    /** ENDIF signals that we are inside some sort of OP_IF structure, which could be
2283
     * or_d, or_c, or_i, andor, d:, or j: wrapper, depending on what follows. We read
2284
     * a BKV_EXPR and then deal with the next opcode case-by-case. */
2285
    ENDIF,
2286
    /** If, inside an ENDIF context, we find an OP_NOTIF before finding an OP_ELSE,
2287
     * we could either be in an or_d or an or_c node. We then check for IFDUP to
2288
     * distinguish these cases. */
2289
    ENDIF_NOTIF,
2290
    /** If, inside an ENDIF context, we find an OP_ELSE, then we could be in either an
2291
     * or_i or an andor node. Read the next BKV_EXPR and find either an OP_IF or an
2292
     * OP_NOTIF. */
2293
    ENDIF_ELSE,
2294
};
2295
2296
//! Parse a miniscript from a bitcoin script
2297
template <typename Key, typename Ctx, typename I>
2298
inline std::optional<Node<Key>> DecodeScript(I& in, I last, const Ctx& ctx)
2299
5.29k
{
2300
    // The two integers are used to hold state for thresh()
2301
5.29k
    std::vector<std::tuple<DecodeContext, int64_t, int64_t>> to_parse;
2302
5.29k
    std::vector<Node<Key>> constructed;
2303
2304
    // This is the top level, so we assume the type is B
2305
    // (in particular, disallowing top level W expressions)
2306
5.29k
    to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2307
2308
5.34M
    while (!to_parse.empty()) {
2309
        // Exit early if the Miniscript is not going to be valid.
2310
5.34M
        if (!constructed.empty() && !constructed.back().IsValid()) return {};
2311
2312
        // Get the current context we are decoding within
2313
5.34M
        auto [cur_context, n, k] = to_parse.back();
2314
5.34M
        to_parse.pop_back();
2315
2316
5.34M
        switch(cur_context) {
2317
2.65M
        case DecodeContext::SINGLE_BKV_EXPR: {
2318
2.65M
            if (in >= last) return {};
2319
2320
            // Constants
2321
2.65M
            if (in[0].first == OP_1) {
2322
80
                ++in;
2323
80
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1);
2324
80
                break;
2325
80
            }
2326
2.65M
            if (in[0].first == OP_0) {
2327
519
                ++in;
2328
519
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
2329
519
                break;
2330
519
            }
2331
            // Public keys
2332
2.65M
            if (in[0].second.size() == 33 || in[0].second.size() == 32) {
2333
5.20k
                auto key = ctx.FromPKBytes(in[0].second.begin(), in[0].second.end());
2334
5.20k
                if (!key) return {};
2335
5.20k
                ++in;
2336
5.20k
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_K, Vector(std::move(*key)));
2337
5.20k
                break;
2338
5.20k
            }
2339
2.65M
            if (last - in >= 5 && in[0].first == OP_VERIFY && in[1].first == OP_EQUAL && in[3].first == OP_HASH160 && in[4].first == OP_DUP && in[2].second.size() == 20) {
2340
730
                auto key = ctx.FromPKHBytes(in[2].second.begin(), in[2].second.end());
2341
730
                if (!key) return {};
2342
727
                in += 5;
2343
727
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_H, Vector(std::move(*key)));
2344
727
                break;
2345
730
            }
2346
            // Time locks
2347
2.65M
            std::optional<int64_t> num;
2348
2.65M
            if (last - in >= 2 && in[0].first == OP_CHECKSEQUENCEVERIFY && (num = ParseScriptNumber(in[1]))) {
2349
2.33k
                in += 2;
2350
2.33k
                if (*num < 1 || *num > 0x7FFFFFFFL) return {};
2351
2.33k
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num);
2352
2.33k
                break;
2353
2.33k
            }
2354
2.64M
            if (last - in >= 2 && in[0].first == OP_CHECKLOCKTIMEVERIFY && (num = ParseScriptNumber(in[1]))) {
2355
1.32k
                in += 2;
2356
1.32k
                if (num < 1 || num > 0x7FFFFFFFL) return {};
2357
1.32k
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num);
2358
1.32k
                break;
2359
1.32k
            }
2360
            // Hashes
2361
2.64M
            if (last - in >= 7 && in[0].first == OP_EQUAL && in[3].first == OP_VERIFY && in[4].first == OP_EQUAL && (num = ParseScriptNumber(in[5])) && num == 32 && in[6].first == OP_SIZE) {
2362
266
                if (in[2].first == OP_SHA256 && in[1].second.size() == 32) {
2363
66
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, in[1].second);
2364
66
                    in += 7;
2365
66
                    break;
2366
200
                } else if (in[2].first == OP_RIPEMD160 && in[1].second.size() == 20) {
2367
55
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::RIPEMD160, in[1].second);
2368
55
                    in += 7;
2369
55
                    break;
2370
145
                } else if (in[2].first == OP_HASH256 && in[1].second.size() == 32) {
2371
86
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, in[1].second);
2372
86
                    in += 7;
2373
86
                    break;
2374
86
                } else if (in[2].first == OP_HASH160 && in[1].second.size() == 20) {
2375
59
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, in[1].second);
2376
59
                    in += 7;
2377
59
                    break;
2378
59
                }
2379
266
            }
2380
            // Multi
2381
2.64M
            if (last - in >= 3 && in[0].first == OP_CHECKMULTISIG) {
2382
126
                if (IsTapscript(ctx.MsContext())) return {};
2383
126
                std::vector<Key> keys;
2384
126
                const auto n = ParseScriptNumber(in[1]);
2385
126
                if (!n || last - in < 3 + *n) return {};
2386
126
                if (*n < 1 || *n > 20) return {};
2387
419
                for (int i = 0; i < *n; ++i) {
2388
293
                    if (in[2 + i].second.size() != 33) return {};
2389
293
                    auto key = ctx.FromPKBytes(in[2 + i].second.begin(), in[2 + i].second.end());
2390
293
                    if (!key) return {};
2391
293
                    keys.push_back(std::move(*key));
2392
293
                }
2393
126
                const auto k = ParseScriptNumber(in[2 + *n]);
2394
126
                if (!k || *k < 1 || *k > *n) return {};
2395
126
                in += 3 + *n;
2396
126
                std::reverse(keys.begin(), keys.end());
2397
126
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), *k);
2398
126
                break;
2399
126
            }
2400
            // Tapscript's equivalent of multi
2401
2.64M
            if (last - in >= 4 && in[0].first == OP_NUMEQUAL) {
2402
792
                if (!IsTapscript(ctx.MsContext())) return {};
2403
                // The necessary threshold of signatures.
2404
792
                const auto k = ParseScriptNumber(in[1]);
2405
792
                if (!k) return {};
2406
792
                if (*k < 1 || *k > MAX_PUBKEYS_PER_MULTI_A) return {};
2407
792
                if (last - in < 2 + *k * 2) return {};
2408
792
                std::vector<Key> keys;
2409
792
                keys.reserve(*k);
2410
                // Walk through the expected (pubkey, CHECKSIG[ADD]) pairs.
2411
89.5k
                for (int pos = 2;; pos += 2) {
2412
89.5k
                    if (last - in < pos + 2) return {};
2413
                    // Make sure it's indeed an x-only pubkey and a CHECKSIG[ADD], then parse the key.
2414
89.5k
                    if (in[pos].first != OP_CHECKSIGADD && in[pos].first != OP_CHECKSIG) return {};
2415
89.5k
                    if (in[pos + 1].second.size() != 32) return {};
2416
89.5k
                    auto key = ctx.FromPKBytes(in[pos + 1].second.begin(), in[pos + 1].second.end());
2417
89.5k
                    if (!key) return {};
2418
89.5k
                    keys.push_back(std::move(*key));
2419
                    // Make sure early we don't parse an arbitrary large expression.
2420
89.5k
                    if (keys.size() > MAX_PUBKEYS_PER_MULTI_A) return {};
2421
                    // OP_CHECKSIG means it was the last one to parse.
2422
89.5k
                    if (in[pos].first == OP_CHECKSIG) break;
2423
89.5k
                }
2424
791
                if (keys.size() < (size_t)*k) return {};
2425
791
                in += 2 + keys.size() * 2;
2426
791
                std::reverse(keys.begin(), keys.end());
2427
791
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), *k);
2428
791
                break;
2429
791
            }
2430
            /** In the following wrappers, we only need to push SINGLE_BKV_EXPR rather
2431
             * than BKV_EXPR, because and_v commutes with these wrappers. For example,
2432
             * c:and_v(X,Y) produces the same script as and_v(X,c:Y). */
2433
            // c: wrapper
2434
2.64M
            if (in[0].first == OP_CHECKSIG) {
2435
5.90k
                ++in;
2436
5.90k
                to_parse.emplace_back(DecodeContext::CHECK, -1, -1);
2437
5.90k
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2438
5.90k
                break;
2439
5.90k
            }
2440
            // v: wrapper
2441
2.64M
            if (in[0].first == OP_VERIFY) {
2442
1.58k
                ++in;
2443
1.58k
                to_parse.emplace_back(DecodeContext::VERIFY, -1, -1);
2444
1.58k
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2445
1.58k
                break;
2446
1.58k
            }
2447
            // n: wrapper
2448
2.63M
            if (in[0].first == OP_0NOTEQUAL) {
2449
2.63M
                ++in;
2450
2.63M
                to_parse.emplace_back(DecodeContext::ZERO_NOTEQUAL, -1, -1);
2451
2.63M
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2452
2.63M
                break;
2453
2.63M
            }
2454
            // Thresh
2455
3.91k
            if (last - in >= 3 && in[0].first == OP_EQUAL && (num = ParseScriptNumber(in[1]))) {
2456
324
                if (*num < 1) return {};
2457
324
                in += 2;
2458
324
                to_parse.emplace_back(DecodeContext::THRESH_W, 0, *num);
2459
324
                break;
2460
324
            }
2461
            // OP_ENDIF can be WRAP_J, WRAP_D, ANDOR, OR_C, OR_D, or OR_I
2462
3.58k
            if (in[0].first == OP_ENDIF) {
2463
827
                ++in;
2464
827
                to_parse.emplace_back(DecodeContext::ENDIF, -1, -1);
2465
827
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2466
827
                break;
2467
827
            }
2468
            /** In and_b and or_b nodes, we only look for SINGLE_BKV_EXPR, because
2469
             * or_b(and_v(X,Y),Z) has script [X] [Y] [Z] OP_BOOLOR, the same as
2470
             * and_v(X,or_b(Y,Z)). In this example, the former of these is invalid as
2471
             * miniscript, while the latter is valid. So we leave the and_v "outside"
2472
             * while decoding. */
2473
            // and_b
2474
2.76k
            if (in[0].first == OP_BOOLAND) {
2475
2.69k
                ++in;
2476
2.69k
                to_parse.emplace_back(DecodeContext::AND_B, -1, -1);
2477
2.69k
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2478
2.69k
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2479
2.69k
                break;
2480
2.69k
            }
2481
            // or_b
2482
68
            if (in[0].first == OP_BOOLOR) {
2483
58
                ++in;
2484
58
                to_parse.emplace_back(DecodeContext::OR_B, -1, -1);
2485
58
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2486
58
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2487
58
                break;
2488
58
            }
2489
            // Unrecognised expression
2490
10
            return {};
2491
68
        }
2492
11.9k
        case DecodeContext::BKV_EXPR: {
2493
11.9k
            to_parse.emplace_back(DecodeContext::MAYBE_AND_V, -1, -1);
2494
11.9k
            to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2495
11.9k
            break;
2496
68
        }
2497
3.73k
        case DecodeContext::W_EXPR: {
2498
            // a: wrapper
2499
3.73k
            if (in >= last) return {};
2500
3.73k
            if (in[0].first == OP_FROMALTSTACK) {
2501
2.94k
                ++in;
2502
2.94k
                to_parse.emplace_back(DecodeContext::ALT, -1, -1);
2503
2.94k
            } else {
2504
789
                to_parse.emplace_back(DecodeContext::SWAP, -1, -1);
2505
789
            }
2506
3.73k
            to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2507
3.73k
            break;
2508
3.73k
        }
2509
11.9k
        case DecodeContext::MAYBE_AND_V: {
2510
            // If we reach a potential AND_V top-level, check if the next part of the script could be another AND_V child
2511
            // These op-codes cannot end any well-formed miniscript so cannot be used in an and_v node.
2512
11.9k
            if (in < last && in[0].first != OP_IF && in[0].first != OP_ELSE && in[0].first != OP_NOTIF && in[0].first != OP_TOALTSTACK && in[0].first != OP_SWAP) {
2513
1.49k
                to_parse.emplace_back(DecodeContext::AND_V, -1, -1);
2514
                // BKV_EXPR can contain more AND_V nodes
2515
1.49k
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2516
1.49k
            }
2517
11.9k
            break;
2518
3.73k
        }
2519
789
        case DecodeContext::SWAP: {
2520
789
            if (in >= last || in[0].first != OP_SWAP || constructed.empty()) return {};
2521
789
            ++in;
2522
789
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S, Vector(std::move(constructed.back()))};
2523
789
            break;
2524
789
        }
2525
2.94k
        case DecodeContext::ALT: {
2526
2.94k
            if (in >= last || in[0].first != OP_TOALTSTACK || constructed.empty()) return {};
2527
2.94k
            ++in;
2528
2.94k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A, Vector(std::move(constructed.back()))};
2529
2.94k
            break;
2530
2.94k
        }
2531
5.89k
        case DecodeContext::CHECK: {
2532
5.89k
            if (constructed.empty()) return {};
2533
5.89k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(std::move(constructed.back()))};
2534
5.89k
            break;
2535
5.89k
        }
2536
86
        case DecodeContext::DUP_IF: {
2537
86
            if (constructed.empty()) return {};
2538
86
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D, Vector(std::move(constructed.back()))};
2539
86
            break;
2540
86
        }
2541
1.58k
        case DecodeContext::VERIFY: {
2542
1.58k
            if (constructed.empty()) return {};
2543
1.58k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V, Vector(std::move(constructed.back()))};
2544
1.58k
            break;
2545
1.58k
        }
2546
8
        case DecodeContext::NON_ZERO: {
2547
8
            if (constructed.empty()) return {};
2548
8
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J, Vector(std::move(constructed.back()))};
2549
8
            break;
2550
8
        }
2551
2.63M
        case DecodeContext::ZERO_NOTEQUAL: {
2552
2.63M
            if (constructed.empty()) return {};
2553
2.63M
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N, Vector(std::move(constructed.back()))};
2554
2.63M
            break;
2555
2.63M
        }
2556
1.48k
        case DecodeContext::AND_V: {
2557
1.48k
            if (constructed.size() < 2) return {};
2558
1.48k
            BuildBack(ctx.MsContext(), Fragment::AND_V, constructed, /*reverse=*/true);
2559
1.48k
            break;
2560
1.48k
        }
2561
2.69k
        case DecodeContext::AND_B: {
2562
2.69k
            if (constructed.size() < 2) return {};
2563
2.69k
            BuildBack(ctx.MsContext(), Fragment::AND_B, constructed, /*reverse=*/true);
2564
2.69k
            break;
2565
2.69k
        }
2566
58
        case DecodeContext::OR_B: {
2567
58
            if (constructed.size() < 2) return {};
2568
58
            BuildBack(ctx.MsContext(), Fragment::OR_B, constructed, /*reverse=*/true);
2569
58
            break;
2570
58
        }
2571
22
        case DecodeContext::OR_C: {
2572
22
            if (constructed.size() < 2) return {};
2573
22
            BuildBack(ctx.MsContext(), Fragment::OR_C, constructed, /*reverse=*/true);
2574
22
            break;
2575
22
        }
2576
63
        case DecodeContext::OR_D: {
2577
63
            if (constructed.size() < 2) return {};
2578
63
            BuildBack(ctx.MsContext(), Fragment::OR_D, constructed, /*reverse=*/true);
2579
63
            break;
2580
63
        }
2581
150
        case DecodeContext::ANDOR: {
2582
150
            if (constructed.size() < 3) return {};
2583
150
            Node left{std::move(constructed.back())};
2584
150
            constructed.pop_back();
2585
150
            Node right{std::move(constructed.back())};
2586
150
            constructed.pop_back();
2587
150
            Node mid{std::move(constructed.back())};
2588
150
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR, Vector(std::move(left), std::move(mid), std::move(right))};
2589
150
            break;
2590
150
        }
2591
1.30k
        case DecodeContext::THRESH_W: {
2592
1.30k
            if (in >= last) return {};
2593
1.30k
            if (in[0].first == OP_ADD) {
2594
978
                ++in;
2595
978
                to_parse.emplace_back(DecodeContext::THRESH_W, n+1, k);
2596
978
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2597
978
            } else {
2598
324
                to_parse.emplace_back(DecodeContext::THRESH_E, n+1, k);
2599
                // All children of thresh have type modifier d, so cannot be and_v
2600
324
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2601
324
            }
2602
1.30k
            break;
2603
1.30k
        }
2604
324
        case DecodeContext::THRESH_E: {
2605
324
            if (k < 1 || k > n || constructed.size() < static_cast<size_t>(n)) return {};
2606
324
            std::vector<Node<Key>> subs;
2607
1.62k
            for (int i = 0; i < n; ++i) {
2608
1.30k
                Node sub{std::move(constructed.back())};
2609
1.30k
                constructed.pop_back();
2610
1.30k
                subs.push_back(std::move(sub));
2611
1.30k
            }
2612
324
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs), k);
2613
324
            break;
2614
324
        }
2615
826
        case DecodeContext::ENDIF: {
2616
826
            if (in >= last) return {};
2617
2618
            // could be andor or or_i
2619
826
            if (in[0].first == OP_ELSE) {
2620
647
                ++in;
2621
647
                to_parse.emplace_back(DecodeContext::ENDIF_ELSE, -1, -1);
2622
647
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2623
647
            }
2624
            // could be j: or d: wrapper
2625
179
            else if (in[0].first == OP_IF) {
2626
94
                if (last - in >= 2 && in[1].first == OP_DUP) {
2627
86
                    in += 2;
2628
86
                    to_parse.emplace_back(DecodeContext::DUP_IF, -1, -1);
2629
86
                } else if (last - in >= 3 && in[1].first == OP_0NOTEQUAL && in[2].first == OP_SIZE) {
2630
8
                    in += 3;
2631
8
                    to_parse.emplace_back(DecodeContext::NON_ZERO, -1, -1);
2632
8
                }
2633
0
                else {
2634
0
                    return {};
2635
0
                }
2636
            // could be or_c or or_d
2637
94
            } else if (in[0].first == OP_NOTIF) {
2638
85
                ++in;
2639
85
                to_parse.emplace_back(DecodeContext::ENDIF_NOTIF, -1, -1);
2640
85
            }
2641
0
            else {
2642
0
                return {};
2643
0
            }
2644
826
            break;
2645
826
        }
2646
826
        case DecodeContext::ENDIF_NOTIF: {
2647
85
            if (in >= last) return {};
2648
85
            if (in[0].first == OP_IFDUP) {
2649
63
                ++in;
2650
63
                to_parse.emplace_back(DecodeContext::OR_D, -1, -1);
2651
63
            } else {
2652
22
                to_parse.emplace_back(DecodeContext::OR_C, -1, -1);
2653
22
            }
2654
            // or_c and or_d both require X to have type modifier d so, can't contain and_v
2655
85
            to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2656
85
            break;
2657
85
        }
2658
647
        case DecodeContext::ENDIF_ELSE: {
2659
647
            if (in >= last) return {};
2660
647
            if (in[0].first == OP_IF) {
2661
497
                ++in;
2662
497
                BuildBack(ctx.MsContext(), Fragment::OR_I, constructed, /*reverse=*/true);
2663
497
            } else if (in[0].first == OP_NOTIF) {
2664
150
                ++in;
2665
150
                to_parse.emplace_back(DecodeContext::ANDOR, -1, -1);
2666
                // andor requires X to have type modifier d, so it can't be and_v
2667
150
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2668
150
            } else {
2669
0
                return {};
2670
0
            }
2671
647
            break;
2672
647
        }
2673
5.34M
        }
2674
5.34M
    }
2675
5.27k
    if (constructed.size() != 1) return {};
2676
5.27k
    Node tl_node{std::move(constructed.front())};
2677
5.27k
    tl_node.DuplicateKeyCheck(ctx);
2678
    // Note that due to how ComputeType works (only assign the type to the node if the
2679
    // subs' types are valid) this would fail if any node of tree is badly typed.
2680
5.27k
    if (!tl_node.IsValidTopLevel()) return {};
2681
5.27k
    return tl_node;
2682
5.27k
}
miniscript_tests.cpp:std::optional<miniscript::Node<CPubKey>> miniscript::internal::DecodeScript<CPubKey, (anonymous namespace)::KeyConverter, __gnu_cxx::__normal_iterator<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>*, std::vector<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>, std::allocator<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>>>>>(__gnu_cxx::__normal_iterator<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>*, std::vector<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>, std::allocator<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>>>>&, __gnu_cxx::__normal_iterator<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>*, std::vector<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>, std::allocator<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>>>>, (anonymous namespace)::KeyConverter const&)
Line
Count
Source
2299
128
{
2300
    // The two integers are used to hold state for thresh()
2301
128
    std::vector<std::tuple<DecodeContext, int64_t, int64_t>> to_parse;
2302
128
    std::vector<Node<Key>> constructed;
2303
2304
    // This is the top level, so we assume the type is B
2305
    // (in particular, disallowing top level W expressions)
2306
128
    to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2307
2308
20.2k
    while (!to_parse.empty()) {
2309
        // Exit early if the Miniscript is not going to be valid.
2310
20.1k
        if (!constructed.empty() && !constructed.back().IsValid()) return {};
2311
2312
        // Get the current context we are decoding within
2313
20.1k
        auto [cur_context, n, k] = to_parse.back();
2314
20.1k
        to_parse.pop_back();
2315
2316
20.1k
        switch(cur_context) {
2317
5.95k
        case DecodeContext::SINGLE_BKV_EXPR: {
2318
5.95k
            if (in >= last) return {};
2319
2320
            // Constants
2321
5.95k
            if (in[0].first == OP_1) {
2322
77
                ++in;
2323
77
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1);
2324
77
                break;
2325
77
            }
2326
5.87k
            if (in[0].first == OP_0) {
2327
83
                ++in;
2328
83
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
2329
83
                break;
2330
83
            }
2331
            // Public keys
2332
5.79k
            if (in[0].second.size() == 33 || in[0].second.size() == 32) {
2333
454
                auto key = ctx.FromPKBytes(in[0].second.begin(), in[0].second.end());
2334
454
                if (!key) return {};
2335
454
                ++in;
2336
454
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_K, Vector(std::move(*key)));
2337
454
                break;
2338
454
            }
2339
5.33k
            if (last - in >= 5 && in[0].first == OP_VERIFY && in[1].first == OP_EQUAL && in[3].first == OP_HASH160 && in[4].first == OP_DUP && in[2].second.size() == 20) {
2340
26
                auto key = ctx.FromPKHBytes(in[2].second.begin(), in[2].second.end());
2341
26
                if (!key) return {};
2342
26
                in += 5;
2343
26
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_H, Vector(std::move(*key)));
2344
26
                break;
2345
26
            }
2346
            // Time locks
2347
5.31k
            std::optional<int64_t> num;
2348
5.31k
            if (last - in >= 2 && in[0].first == OP_CHECKSEQUENCEVERIFY && (num = ParseScriptNumber(in[1]))) {
2349
2.03k
                in += 2;
2350
2.03k
                if (*num < 1 || *num > 0x7FFFFFFFL) return {};
2351
2.03k
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num);
2352
2.03k
                break;
2353
2.03k
            }
2354
3.27k
            if (last - in >= 2 && in[0].first == OP_CHECKLOCKTIMEVERIFY && (num = ParseScriptNumber(in[1]))) {
2355
65
                in += 2;
2356
65
                if (num < 1 || num > 0x7FFFFFFFL) return {};
2357
65
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num);
2358
65
                break;
2359
65
            }
2360
            // Hashes
2361
3.21k
            if (last - in >= 7 && in[0].first == OP_EQUAL && in[3].first == OP_VERIFY && in[4].first == OP_EQUAL && (num = ParseScriptNumber(in[5])) && num == 32 && in[6].first == OP_SIZE) {
2362
48
                if (in[2].first == OP_SHA256 && in[1].second.size() == 32) {
2363
21
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, in[1].second);
2364
21
                    in += 7;
2365
21
                    break;
2366
27
                } else if (in[2].first == OP_RIPEMD160 && in[1].second.size() == 20) {
2367
7
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::RIPEMD160, in[1].second);
2368
7
                    in += 7;
2369
7
                    break;
2370
20
                } else if (in[2].first == OP_HASH256 && in[1].second.size() == 32) {
2371
14
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, in[1].second);
2372
14
                    in += 7;
2373
14
                    break;
2374
14
                } else if (in[2].first == OP_HASH160 && in[1].second.size() == 20) {
2375
6
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, in[1].second);
2376
6
                    in += 7;
2377
6
                    break;
2378
6
                }
2379
48
            }
2380
            // Multi
2381
3.16k
            if (last - in >= 3 && in[0].first == OP_CHECKMULTISIG) {
2382
12
                if (IsTapscript(ctx.MsContext())) return {};
2383
12
                std::vector<Key> keys;
2384
12
                const auto n = ParseScriptNumber(in[1]);
2385
12
                if (!n || last - in < 3 + *n) return {};
2386
12
                if (*n < 1 || *n > 20) return {};
2387
35
                for (int i = 0; i < *n; ++i) {
2388
23
                    if (in[2 + i].second.size() != 33) return {};
2389
23
                    auto key = ctx.FromPKBytes(in[2 + i].second.begin(), in[2 + i].second.end());
2390
23
                    if (!key) return {};
2391
23
                    keys.push_back(std::move(*key));
2392
23
                }
2393
12
                const auto k = ParseScriptNumber(in[2 + *n]);
2394
12
                if (!k || *k < 1 || *k > *n) return {};
2395
12
                in += 3 + *n;
2396
12
                std::reverse(keys.begin(), keys.end());
2397
12
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), *k);
2398
12
                break;
2399
12
            }
2400
            // Tapscript's equivalent of multi
2401
3.15k
            if (last - in >= 4 && in[0].first == OP_NUMEQUAL) {
2402
4
                if (!IsTapscript(ctx.MsContext())) return {};
2403
                // The necessary threshold of signatures.
2404
4
                const auto k = ParseScriptNumber(in[1]);
2405
4
                if (!k) return {};
2406
4
                if (*k < 1 || *k > MAX_PUBKEYS_PER_MULTI_A) return {};
2407
4
                if (last - in < 2 + *k * 2) return {};
2408
4
                std::vector<Key> keys;
2409
4
                keys.reserve(*k);
2410
                // Walk through the expected (pubkey, CHECKSIG[ADD]) pairs.
2411
27
                for (int pos = 2;; pos += 2) {
2412
27
                    if (last - in < pos + 2) return {};
2413
                    // Make sure it's indeed an x-only pubkey and a CHECKSIG[ADD], then parse the key.
2414
26
                    if (in[pos].first != OP_CHECKSIGADD && in[pos].first != OP_CHECKSIG) return {};
2415
26
                    if (in[pos + 1].second.size() != 32) return {};
2416
26
                    auto key = ctx.FromPKBytes(in[pos + 1].second.begin(), in[pos + 1].second.end());
2417
26
                    if (!key) return {};
2418
26
                    keys.push_back(std::move(*key));
2419
                    // Make sure early we don't parse an arbitrary large expression.
2420
26
                    if (keys.size() > MAX_PUBKEYS_PER_MULTI_A) return {};
2421
                    // OP_CHECKSIG means it was the last one to parse.
2422
26
                    if (in[pos].first == OP_CHECKSIG) break;
2423
26
                }
2424
3
                if (keys.size() < (size_t)*k) return {};
2425
3
                in += 2 + keys.size() * 2;
2426
3
                std::reverse(keys.begin(), keys.end());
2427
3
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), *k);
2428
3
                break;
2429
3
            }
2430
            /** In the following wrappers, we only need to push SINGLE_BKV_EXPR rather
2431
             * than BKV_EXPR, because and_v commutes with these wrappers. For example,
2432
             * c:and_v(X,Y) produces the same script as and_v(X,c:Y). */
2433
            // c: wrapper
2434
3.14k
            if (in[0].first == OP_CHECKSIG) {
2435
465
                ++in;
2436
465
                to_parse.emplace_back(DecodeContext::CHECK, -1, -1);
2437
465
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2438
465
                break;
2439
465
            }
2440
            // v: wrapper
2441
2.68k
            if (in[0].first == OP_VERIFY) {
2442
81
                ++in;
2443
81
                to_parse.emplace_back(DecodeContext::VERIFY, -1, -1);
2444
81
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2445
81
                break;
2446
81
            }
2447
            // n: wrapper
2448
2.60k
            if (in[0].first == OP_0NOTEQUAL) {
2449
15
                ++in;
2450
15
                to_parse.emplace_back(DecodeContext::ZERO_NOTEQUAL, -1, -1);
2451
15
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2452
15
                break;
2453
15
            }
2454
            // Thresh
2455
2.58k
            if (last - in >= 3 && in[0].first == OP_EQUAL && (num = ParseScriptNumber(in[1]))) {
2456
16
                if (*num < 1) return {};
2457
16
                in += 2;
2458
16
                to_parse.emplace_back(DecodeContext::THRESH_W, 0, *num);
2459
16
                break;
2460
16
            }
2461
            // OP_ENDIF can be WRAP_J, WRAP_D, ANDOR, OR_C, OR_D, or OR_I
2462
2.56k
            if (in[0].first == OP_ENDIF) {
2463
142
                ++in;
2464
142
                to_parse.emplace_back(DecodeContext::ENDIF, -1, -1);
2465
142
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2466
142
                break;
2467
142
            }
2468
            /** In and_b and or_b nodes, we only look for SINGLE_BKV_EXPR, because
2469
             * or_b(and_v(X,Y),Z) has script [X] [Y] [Z] OP_BOOLOR, the same as
2470
             * and_v(X,or_b(Y,Z)). In this example, the former of these is invalid as
2471
             * miniscript, while the latter is valid. So we leave the and_v "outside"
2472
             * while decoding. */
2473
            // and_b
2474
2.42k
            if (in[0].first == OP_BOOLAND) {
2475
2.41k
                ++in;
2476
2.41k
                to_parse.emplace_back(DecodeContext::AND_B, -1, -1);
2477
2.41k
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2478
2.41k
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2479
2.41k
                break;
2480
2.41k
            }
2481
            // or_b
2482
9
            if (in[0].first == OP_BOOLOR) {
2483
8
                ++in;
2484
8
                to_parse.emplace_back(DecodeContext::OR_B, -1, -1);
2485
8
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2486
8
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2487
8
                break;
2488
8
            }
2489
            // Unrecognised expression
2490
1
            return {};
2491
9
        }
2492
2.90k
        case DecodeContext::BKV_EXPR: {
2493
2.90k
            to_parse.emplace_back(DecodeContext::MAYBE_AND_V, -1, -1);
2494
2.90k
            to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2495
2.90k
            break;
2496
9
        }
2497
2.45k
        case DecodeContext::W_EXPR: {
2498
            // a: wrapper
2499
2.45k
            if (in >= last) return {};
2500
2.45k
            if (in[0].first == OP_FROMALTSTACK) {
2501
2.44k
                ++in;
2502
2.44k
                to_parse.emplace_back(DecodeContext::ALT, -1, -1);
2503
2.44k
            } else {
2504
10
                to_parse.emplace_back(DecodeContext::SWAP, -1, -1);
2505
10
            }
2506
2.45k
            to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2507
2.45k
            break;
2508
2.45k
        }
2509
2.89k
        case DecodeContext::MAYBE_AND_V: {
2510
            // If we reach a potential AND_V top-level, check if the next part of the script could be another AND_V child
2511
            // These op-codes cannot end any well-formed miniscript so cannot be used in an and_v node.
2512
2.89k
            if (in < last && in[0].first != OP_IF && in[0].first != OP_ELSE && in[0].first != OP_NOTIF && in[0].first != OP_TOALTSTACK && in[0].first != OP_SWAP) {
2513
67
                to_parse.emplace_back(DecodeContext::AND_V, -1, -1);
2514
                // BKV_EXPR can contain more AND_V nodes
2515
67
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2516
67
            }
2517
2.89k
            break;
2518
2.45k
        }
2519
10
        case DecodeContext::SWAP: {
2520
10
            if (in >= last || in[0].first != OP_SWAP || constructed.empty()) return {};
2521
10
            ++in;
2522
10
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S, Vector(std::move(constructed.back()))};
2523
10
            break;
2524
10
        }
2525
2.44k
        case DecodeContext::ALT: {
2526
2.44k
            if (in >= last || in[0].first != OP_TOALTSTACK || constructed.empty()) return {};
2527
2.44k
            ++in;
2528
2.44k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A, Vector(std::move(constructed.back()))};
2529
2.44k
            break;
2530
2.44k
        }
2531
464
        case DecodeContext::CHECK: {
2532
464
            if (constructed.empty()) return {};
2533
464
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(std::move(constructed.back()))};
2534
464
            break;
2535
464
        }
2536
5
        case DecodeContext::DUP_IF: {
2537
5
            if (constructed.empty()) return {};
2538
5
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D, Vector(std::move(constructed.back()))};
2539
5
            break;
2540
5
        }
2541
81
        case DecodeContext::VERIFY: {
2542
81
            if (constructed.empty()) return {};
2543
81
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V, Vector(std::move(constructed.back()))};
2544
81
            break;
2545
81
        }
2546
8
        case DecodeContext::NON_ZERO: {
2547
8
            if (constructed.empty()) return {};
2548
8
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J, Vector(std::move(constructed.back()))};
2549
8
            break;
2550
8
        }
2551
15
        case DecodeContext::ZERO_NOTEQUAL: {
2552
15
            if (constructed.empty()) return {};
2553
15
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N, Vector(std::move(constructed.back()))};
2554
15
            break;
2555
15
        }
2556
66
        case DecodeContext::AND_V: {
2557
66
            if (constructed.size() < 2) return {};
2558
66
            BuildBack(ctx.MsContext(), Fragment::AND_V, constructed, /*reverse=*/true);
2559
66
            break;
2560
66
        }
2561
2.41k
        case DecodeContext::AND_B: {
2562
2.41k
            if (constructed.size() < 2) return {};
2563
2.41k
            BuildBack(ctx.MsContext(), Fragment::AND_B, constructed, /*reverse=*/true);
2564
2.41k
            break;
2565
2.41k
        }
2566
8
        case DecodeContext::OR_B: {
2567
8
            if (constructed.size() < 2) return {};
2568
8
            BuildBack(ctx.MsContext(), Fragment::OR_B, constructed, /*reverse=*/true);
2569
8
            break;
2570
8
        }
2571
6
        case DecodeContext::OR_C: {
2572
6
            if (constructed.size() < 2) return {};
2573
6
            BuildBack(ctx.MsContext(), Fragment::OR_C, constructed, /*reverse=*/true);
2574
6
            break;
2575
6
        }
2576
15
        case DecodeContext::OR_D: {
2577
15
            if (constructed.size() < 2) return {};
2578
15
            BuildBack(ctx.MsContext(), Fragment::OR_D, constructed, /*reverse=*/true);
2579
15
            break;
2580
15
        }
2581
29
        case DecodeContext::ANDOR: {
2582
29
            if (constructed.size() < 3) return {};
2583
29
            Node left{std::move(constructed.back())};
2584
29
            constructed.pop_back();
2585
29
            Node right{std::move(constructed.back())};
2586
29
            constructed.pop_back();
2587
29
            Node mid{std::move(constructed.back())};
2588
29
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR, Vector(std::move(left), std::move(mid), std::move(right))};
2589
29
            break;
2590
29
        }
2591
46
        case DecodeContext::THRESH_W: {
2592
46
            if (in >= last) return {};
2593
46
            if (in[0].first == OP_ADD) {
2594
30
                ++in;
2595
30
                to_parse.emplace_back(DecodeContext::THRESH_W, n+1, k);
2596
30
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2597
30
            } else {
2598
16
                to_parse.emplace_back(DecodeContext::THRESH_E, n+1, k);
2599
                // All children of thresh have type modifier d, so cannot be and_v
2600
16
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2601
16
            }
2602
46
            break;
2603
46
        }
2604
16
        case DecodeContext::THRESH_E: {
2605
16
            if (k < 1 || k > n || constructed.size() < static_cast<size_t>(n)) return {};
2606
16
            std::vector<Node<Key>> subs;
2607
62
            for (int i = 0; i < n; ++i) {
2608
46
                Node sub{std::move(constructed.back())};
2609
46
                constructed.pop_back();
2610
46
                subs.push_back(std::move(sub));
2611
46
            }
2612
16
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs), k);
2613
16
            break;
2614
16
        }
2615
142
        case DecodeContext::ENDIF: {
2616
142
            if (in >= last) return {};
2617
2618
            // could be andor or or_i
2619
142
            if (in[0].first == OP_ELSE) {
2620
108
                ++in;
2621
108
                to_parse.emplace_back(DecodeContext::ENDIF_ELSE, -1, -1);
2622
108
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2623
108
            }
2624
            // could be j: or d: wrapper
2625
34
            else if (in[0].first == OP_IF) {
2626
13
                if (last - in >= 2 && in[1].first == OP_DUP) {
2627
5
                    in += 2;
2628
5
                    to_parse.emplace_back(DecodeContext::DUP_IF, -1, -1);
2629
8
                } else if (last - in >= 3 && in[1].first == OP_0NOTEQUAL && in[2].first == OP_SIZE) {
2630
8
                    in += 3;
2631
8
                    to_parse.emplace_back(DecodeContext::NON_ZERO, -1, -1);
2632
8
                }
2633
0
                else {
2634
0
                    return {};
2635
0
                }
2636
            // could be or_c or or_d
2637
21
            } else if (in[0].first == OP_NOTIF) {
2638
21
                ++in;
2639
21
                to_parse.emplace_back(DecodeContext::ENDIF_NOTIF, -1, -1);
2640
21
            }
2641
0
            else {
2642
0
                return {};
2643
0
            }
2644
142
            break;
2645
142
        }
2646
142
        case DecodeContext::ENDIF_NOTIF: {
2647
21
            if (in >= last) return {};
2648
21
            if (in[0].first == OP_IFDUP) {
2649
15
                ++in;
2650
15
                to_parse.emplace_back(DecodeContext::OR_D, -1, -1);
2651
15
            } else {
2652
6
                to_parse.emplace_back(DecodeContext::OR_C, -1, -1);
2653
6
            }
2654
            // or_c and or_d both require X to have type modifier d so, can't contain and_v
2655
21
            to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2656
21
            break;
2657
21
        }
2658
108
        case DecodeContext::ENDIF_ELSE: {
2659
108
            if (in >= last) return {};
2660
108
            if (in[0].first == OP_IF) {
2661
79
                ++in;
2662
79
                BuildBack(ctx.MsContext(), Fragment::OR_I, constructed, /*reverse=*/true);
2663
79
            } else if (in[0].first == OP_NOTIF) {
2664
29
                ++in;
2665
29
                to_parse.emplace_back(DecodeContext::ANDOR, -1, -1);
2666
                // andor requires X to have type modifier d, so it can't be and_v
2667
29
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2668
29
            } else {
2669
0
                return {};
2670
0
            }
2671
108
            break;
2672
108
        }
2673
20.1k
        }
2674
20.1k
    }
2675
125
    if (constructed.size() != 1) return {};
2676
125
    Node tl_node{std::move(constructed.front())};
2677
125
    tl_node.DuplicateKeyCheck(ctx);
2678
    // Note that due to how ComputeType works (only assign the type to the node if the
2679
    // subs' types are valid) this would fail if any node of tree is badly typed.
2680
125
    if (!tl_node.IsValidTopLevel()) return {};
2681
125
    return tl_node;
2682
125
}
descriptor.cpp:std::optional<miniscript::Node<unsigned int>> miniscript::internal::DecodeScript<unsigned int, (anonymous namespace)::KeyParser, __gnu_cxx::__normal_iterator<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>*, std::vector<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>, std::allocator<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>>>>>(__gnu_cxx::__normal_iterator<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>*, std::vector<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>, std::allocator<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>>>>&, __gnu_cxx::__normal_iterator<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>*, std::vector<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>, std::allocator<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>>>>, (anonymous namespace)::KeyParser const&)
Line
Count
Source
2299
618
{
2300
    // The two integers are used to hold state for thresh()
2301
618
    std::vector<std::tuple<DecodeContext, int64_t, int64_t>> to_parse;
2302
618
    std::vector<Node<Key>> constructed;
2303
2304
    // This is the top level, so we assume the type is B
2305
    // (in particular, disallowing top level W expressions)
2306
618
    to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2307
2308
1.33M
    while (!to_parse.empty()) {
2309
        // Exit early if the Miniscript is not going to be valid.
2310
1.33M
        if (!constructed.empty() && !constructed.back().IsValid()) return {};
2311
2312
        // Get the current context we are decoding within
2313
1.33M
        auto [cur_context, n, k] = to_parse.back();
2314
1.33M
        to_parse.pop_back();
2315
2316
1.33M
        switch(cur_context) {
2317
663k
        case DecodeContext::SINGLE_BKV_EXPR: {
2318
663k
            if (in >= last) return {};
2319
2320
            // Constants
2321
663k
            if (in[0].first == OP_1) {
2322
3
                ++in;
2323
3
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1);
2324
3
                break;
2325
3
            }
2326
663k
            if (in[0].first == OP_0) {
2327
193
                ++in;
2328
193
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
2329
193
                break;
2330
193
            }
2331
            // Public keys
2332
663k
            if (in[0].second.size() == 33 || in[0].second.size() == 32) {
2333
921
                auto key = ctx.FromPKBytes(in[0].second.begin(), in[0].second.end());
2334
921
                if (!key) return {};
2335
919
                ++in;
2336
919
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_K, Vector(std::move(*key)));
2337
919
                break;
2338
921
            }
2339
662k
            if (last - in >= 5 && in[0].first == OP_VERIFY && in[1].first == OP_EQUAL && in[3].first == OP_HASH160 && in[4].first == OP_DUP && in[2].second.size() == 20) {
2340
298
                auto key = ctx.FromPKHBytes(in[2].second.begin(), in[2].second.end());
2341
298
                if (!key) return {};
2342
296
                in += 5;
2343
296
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_H, Vector(std::move(*key)));
2344
296
                break;
2345
298
            }
2346
            // Time locks
2347
662k
            std::optional<int64_t> num;
2348
662k
            if (last - in >= 2 && in[0].first == OP_CHECKSEQUENCEVERIFY && (num = ParseScriptNumber(in[1]))) {
2349
188
                in += 2;
2350
188
                if (*num < 1 || *num > 0x7FFFFFFFL) return {};
2351
188
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num);
2352
188
                break;
2353
188
            }
2354
662k
            if (last - in >= 2 && in[0].first == OP_CHECKLOCKTIMEVERIFY && (num = ParseScriptNumber(in[1]))) {
2355
230
                in += 2;
2356
230
                if (num < 1 || num > 0x7FFFFFFFL) return {};
2357
230
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num);
2358
230
                break;
2359
230
            }
2360
            // Hashes
2361
661k
            if (last - in >= 7 && in[0].first == OP_EQUAL && in[3].first == OP_VERIFY && in[4].first == OP_EQUAL && (num = ParseScriptNumber(in[5])) && num == 32 && in[6].first == OP_SIZE) {
2362
153
                if (in[2].first == OP_SHA256 && in[1].second.size() == 32) {
2363
28
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, in[1].second);
2364
28
                    in += 7;
2365
28
                    break;
2366
125
                } else if (in[2].first == OP_RIPEMD160 && in[1].second.size() == 20) {
2367
36
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::RIPEMD160, in[1].second);
2368
36
                    in += 7;
2369
36
                    break;
2370
89
                } else if (in[2].first == OP_HASH256 && in[1].second.size() == 32) {
2371
48
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, in[1].second);
2372
48
                    in += 7;
2373
48
                    break;
2374
48
                } else if (in[2].first == OP_HASH160 && in[1].second.size() == 20) {
2375
41
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, in[1].second);
2376
41
                    in += 7;
2377
41
                    break;
2378
41
                }
2379
153
            }
2380
            // Multi
2381
661k
            if (last - in >= 3 && in[0].first == OP_CHECKMULTISIG) {
2382
90
                if (IsTapscript(ctx.MsContext())) return {};
2383
90
                std::vector<Key> keys;
2384
90
                const auto n = ParseScriptNumber(in[1]);
2385
90
                if (!n || last - in < 3 + *n) return {};
2386
90
                if (*n < 1 || *n > 20) return {};
2387
312
                for (int i = 0; i < *n; ++i) {
2388
222
                    if (in[2 + i].second.size() != 33) return {};
2389
222
                    auto key = ctx.FromPKBytes(in[2 + i].second.begin(), in[2 + i].second.end());
2390
222
                    if (!key) return {};
2391
222
                    keys.push_back(std::move(*key));
2392
222
                }
2393
90
                const auto k = ParseScriptNumber(in[2 + *n]);
2394
90
                if (!k || *k < 1 || *k > *n) return {};
2395
90
                in += 3 + *n;
2396
90
                std::reverse(keys.begin(), keys.end());
2397
90
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), *k);
2398
90
                break;
2399
90
            }
2400
            // Tapscript's equivalent of multi
2401
661k
            if (last - in >= 4 && in[0].first == OP_NUMEQUAL) {
2402
4
                if (!IsTapscript(ctx.MsContext())) return {};
2403
                // The necessary threshold of signatures.
2404
4
                const auto k = ParseScriptNumber(in[1]);
2405
4
                if (!k) return {};
2406
4
                if (*k < 1 || *k > MAX_PUBKEYS_PER_MULTI_A) return {};
2407
4
                if (last - in < 2 + *k * 2) return {};
2408
4
                std::vector<Key> keys;
2409
4
                keys.reserve(*k);
2410
                // Walk through the expected (pubkey, CHECKSIG[ADD]) pairs.
2411
8
                for (int pos = 2;; pos += 2) {
2412
8
                    if (last - in < pos + 2) return {};
2413
                    // Make sure it's indeed an x-only pubkey and a CHECKSIG[ADD], then parse the key.
2414
8
                    if (in[pos].first != OP_CHECKSIGADD && in[pos].first != OP_CHECKSIG) return {};
2415
8
                    if (in[pos + 1].second.size() != 32) return {};
2416
8
                    auto key = ctx.FromPKBytes(in[pos + 1].second.begin(), in[pos + 1].second.end());
2417
8
                    if (!key) return {};
2418
8
                    keys.push_back(std::move(*key));
2419
                    // Make sure early we don't parse an arbitrary large expression.
2420
8
                    if (keys.size() > MAX_PUBKEYS_PER_MULTI_A) return {};
2421
                    // OP_CHECKSIG means it was the last one to parse.
2422
8
                    if (in[pos].first == OP_CHECKSIG) break;
2423
8
                }
2424
4
                if (keys.size() < (size_t)*k) return {};
2425
4
                in += 2 + keys.size() * 2;
2426
4
                std::reverse(keys.begin(), keys.end());
2427
4
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), *k);
2428
4
                break;
2429
4
            }
2430
            /** In the following wrappers, we only need to push SINGLE_BKV_EXPR rather
2431
             * than BKV_EXPR, because and_v commutes with these wrappers. For example,
2432
             * c:and_v(X,Y) produces the same script as and_v(X,c:Y). */
2433
            // c: wrapper
2434
661k
            if (in[0].first == OP_CHECKSIG) {
2435
1.20k
                ++in;
2436
1.20k
                to_parse.emplace_back(DecodeContext::CHECK, -1, -1);
2437
1.20k
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2438
1.20k
                break;
2439
1.20k
            }
2440
            // v: wrapper
2441
660k
            if (in[0].first == OP_VERIFY) {
2442
490
                ++in;
2443
490
                to_parse.emplace_back(DecodeContext::VERIFY, -1, -1);
2444
490
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2445
490
                break;
2446
490
            }
2447
            // n: wrapper
2448
659k
            if (in[0].first == OP_0NOTEQUAL) {
2449
659k
                ++in;
2450
659k
                to_parse.emplace_back(DecodeContext::ZERO_NOTEQUAL, -1, -1);
2451
659k
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2452
659k
                break;
2453
659k
            }
2454
            // Thresh
2455
763
            if (last - in >= 3 && in[0].first == OP_EQUAL && (num = ParseScriptNumber(in[1]))) {
2456
174
                if (*num < 1) return {};
2457
174
                in += 2;
2458
174
                to_parse.emplace_back(DecodeContext::THRESH_W, 0, *num);
2459
174
                break;
2460
174
            }
2461
            // OP_ENDIF can be WRAP_J, WRAP_D, ANDOR, OR_C, OR_D, or OR_I
2462
589
            if (in[0].first == OP_ENDIF) {
2463
383
                ++in;
2464
383
                to_parse.emplace_back(DecodeContext::ENDIF, -1, -1);
2465
383
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2466
383
                break;
2467
383
            }
2468
            /** In and_b and or_b nodes, we only look for SINGLE_BKV_EXPR, because
2469
             * or_b(and_v(X,Y),Z) has script [X] [Y] [Z] OP_BOOLOR, the same as
2470
             * and_v(X,or_b(Y,Z)). In this example, the former of these is invalid as
2471
             * miniscript, while the latter is valid. So we leave the and_v "outside"
2472
             * while decoding. */
2473
            // and_b
2474
206
            if (in[0].first == OP_BOOLAND) {
2475
176
                ++in;
2476
176
                to_parse.emplace_back(DecodeContext::AND_B, -1, -1);
2477
176
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2478
176
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2479
176
                break;
2480
176
            }
2481
            // or_b
2482
30
            if (in[0].first == OP_BOOLOR) {
2483
22
                ++in;
2484
22
                to_parse.emplace_back(DecodeContext::OR_B, -1, -1);
2485
22
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2486
22
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2487
22
                break;
2488
22
            }
2489
            // Unrecognised expression
2490
8
            return {};
2491
30
        }
2492
2.32k
        case DecodeContext::BKV_EXPR: {
2493
2.32k
            to_parse.emplace_back(DecodeContext::MAYBE_AND_V, -1, -1);
2494
2.32k
            to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2495
2.32k
            break;
2496
30
        }
2497
616
        case DecodeContext::W_EXPR: {
2498
            // a: wrapper
2499
616
            if (in >= last) return {};
2500
616
            if (in[0].first == OP_FROMALTSTACK) {
2501
334
                ++in;
2502
334
                to_parse.emplace_back(DecodeContext::ALT, -1, -1);
2503
334
            } else {
2504
282
                to_parse.emplace_back(DecodeContext::SWAP, -1, -1);
2505
282
            }
2506
616
            to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2507
616
            break;
2508
616
        }
2509
2.31k
        case DecodeContext::MAYBE_AND_V: {
2510
            // If we reach a potential AND_V top-level, check if the next part of the script could be another AND_V child
2511
            // These op-codes cannot end any well-formed miniscript so cannot be used in an and_v node.
2512
2.31k
            if (in < last && in[0].first != OP_IF && in[0].first != OP_ELSE && in[0].first != OP_NOTIF && in[0].first != OP_TOALTSTACK && in[0].first != OP_SWAP) {
2513
441
                to_parse.emplace_back(DecodeContext::AND_V, -1, -1);
2514
                // BKV_EXPR can contain more AND_V nodes
2515
441
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2516
441
            }
2517
2.31k
            break;
2518
616
        }
2519
282
        case DecodeContext::SWAP: {
2520
282
            if (in >= last || in[0].first != OP_SWAP || constructed.empty()) return {};
2521
282
            ++in;
2522
282
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S, Vector(std::move(constructed.back()))};
2523
282
            break;
2524
282
        }
2525
334
        case DecodeContext::ALT: {
2526
334
            if (in >= last || in[0].first != OP_TOALTSTACK || constructed.empty()) return {};
2527
334
            ++in;
2528
334
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A, Vector(std::move(constructed.back()))};
2529
334
            break;
2530
334
        }
2531
1.20k
        case DecodeContext::CHECK: {
2532
1.20k
            if (constructed.empty()) return {};
2533
1.20k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(std::move(constructed.back()))};
2534
1.20k
            break;
2535
1.20k
        }
2536
52
        case DecodeContext::DUP_IF: {
2537
52
            if (constructed.empty()) return {};
2538
52
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D, Vector(std::move(constructed.back()))};
2539
52
            break;
2540
52
        }
2541
490
        case DecodeContext::VERIFY: {
2542
490
            if (constructed.empty()) return {};
2543
490
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V, Vector(std::move(constructed.back()))};
2544
490
            break;
2545
490
        }
2546
0
        case DecodeContext::NON_ZERO: {
2547
0
            if (constructed.empty()) return {};
2548
0
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J, Vector(std::move(constructed.back()))};
2549
0
            break;
2550
0
        }
2551
659k
        case DecodeContext::ZERO_NOTEQUAL: {
2552
659k
            if (constructed.empty()) return {};
2553
659k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N, Vector(std::move(constructed.back()))};
2554
659k
            break;
2555
659k
        }
2556
439
        case DecodeContext::AND_V: {
2557
439
            if (constructed.size() < 2) return {};
2558
439
            BuildBack(ctx.MsContext(), Fragment::AND_V, constructed, /*reverse=*/true);
2559
439
            break;
2560
439
        }
2561
176
        case DecodeContext::AND_B: {
2562
176
            if (constructed.size() < 2) return {};
2563
176
            BuildBack(ctx.MsContext(), Fragment::AND_B, constructed, /*reverse=*/true);
2564
176
            break;
2565
176
        }
2566
22
        case DecodeContext::OR_B: {
2567
22
            if (constructed.size() < 2) return {};
2568
22
            BuildBack(ctx.MsContext(), Fragment::OR_B, constructed, /*reverse=*/true);
2569
22
            break;
2570
22
        }
2571
16
        case DecodeContext::OR_C: {
2572
16
            if (constructed.size() < 2) return {};
2573
16
            BuildBack(ctx.MsContext(), Fragment::OR_C, constructed, /*reverse=*/true);
2574
16
            break;
2575
16
        }
2576
43
        case DecodeContext::OR_D: {
2577
43
            if (constructed.size() < 2) return {};
2578
43
            BuildBack(ctx.MsContext(), Fragment::OR_D, constructed, /*reverse=*/true);
2579
43
            break;
2580
43
        }
2581
83
        case DecodeContext::ANDOR: {
2582
83
            if (constructed.size() < 3) return {};
2583
83
            Node left{std::move(constructed.back())};
2584
83
            constructed.pop_back();
2585
83
            Node right{std::move(constructed.back())};
2586
83
            constructed.pop_back();
2587
83
            Node mid{std::move(constructed.back())};
2588
83
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR, Vector(std::move(left), std::move(mid), std::move(right))};
2589
83
            break;
2590
83
        }
2591
592
        case DecodeContext::THRESH_W: {
2592
592
            if (in >= last) return {};
2593
592
            if (in[0].first == OP_ADD) {
2594
418
                ++in;
2595
418
                to_parse.emplace_back(DecodeContext::THRESH_W, n+1, k);
2596
418
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2597
418
            } else {
2598
174
                to_parse.emplace_back(DecodeContext::THRESH_E, n+1, k);
2599
                // All children of thresh have type modifier d, so cannot be and_v
2600
174
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2601
174
            }
2602
592
            break;
2603
592
        }
2604
174
        case DecodeContext::THRESH_E: {
2605
174
            if (k < 1 || k > n || constructed.size() < static_cast<size_t>(n)) return {};
2606
174
            std::vector<Node<Key>> subs;
2607
766
            for (int i = 0; i < n; ++i) {
2608
592
                Node sub{std::move(constructed.back())};
2609
592
                constructed.pop_back();
2610
592
                subs.push_back(std::move(sub));
2611
592
            }
2612
174
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs), k);
2613
174
            break;
2614
174
        }
2615
382
        case DecodeContext::ENDIF: {
2616
382
            if (in >= last) return {};
2617
2618
            // could be andor or or_i
2619
382
            if (in[0].first == OP_ELSE) {
2620
271
                ++in;
2621
271
                to_parse.emplace_back(DecodeContext::ENDIF_ELSE, -1, -1);
2622
271
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2623
271
            }
2624
            // could be j: or d: wrapper
2625
111
            else if (in[0].first == OP_IF) {
2626
52
                if (last - in >= 2 && in[1].first == OP_DUP) {
2627
52
                    in += 2;
2628
52
                    to_parse.emplace_back(DecodeContext::DUP_IF, -1, -1);
2629
52
                } else if (last - in >= 3 && in[1].first == OP_0NOTEQUAL && in[2].first == OP_SIZE) {
2630
0
                    in += 3;
2631
0
                    to_parse.emplace_back(DecodeContext::NON_ZERO, -1, -1);
2632
0
                }
2633
0
                else {
2634
0
                    return {};
2635
0
                }
2636
            // could be or_c or or_d
2637
59
            } else if (in[0].first == OP_NOTIF) {
2638
59
                ++in;
2639
59
                to_parse.emplace_back(DecodeContext::ENDIF_NOTIF, -1, -1);
2640
59
            }
2641
0
            else {
2642
0
                return {};
2643
0
            }
2644
382
            break;
2645
382
        }
2646
382
        case DecodeContext::ENDIF_NOTIF: {
2647
59
            if (in >= last) return {};
2648
59
            if (in[0].first == OP_IFDUP) {
2649
43
                ++in;
2650
43
                to_parse.emplace_back(DecodeContext::OR_D, -1, -1);
2651
43
            } else {
2652
16
                to_parse.emplace_back(DecodeContext::OR_C, -1, -1);
2653
16
            }
2654
            // or_c and or_d both require X to have type modifier d so, can't contain and_v
2655
59
            to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2656
59
            break;
2657
59
        }
2658
271
        case DecodeContext::ENDIF_ELSE: {
2659
271
            if (in >= last) return {};
2660
271
            if (in[0].first == OP_IF) {
2661
188
                ++in;
2662
188
                BuildBack(ctx.MsContext(), Fragment::OR_I, constructed, /*reverse=*/true);
2663
188
            } else if (in[0].first == OP_NOTIF) {
2664
83
                ++in;
2665
83
                to_parse.emplace_back(DecodeContext::ANDOR, -1, -1);
2666
                // andor requires X to have type modifier d, so it can't be and_v
2667
83
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2668
83
            } else {
2669
0
                return {};
2670
0
            }
2671
271
            break;
2672
271
        }
2673
1.33M
        }
2674
1.33M
    }
2675
606
    if (constructed.size() != 1) return {};
2676
606
    Node tl_node{std::move(constructed.front())};
2677
606
    tl_node.DuplicateKeyCheck(ctx);
2678
    // Note that due to how ComputeType works (only assign the type to the node if the
2679
    // subs' types are valid) this would fail if any node of tree is badly typed.
2680
606
    if (!tl_node.IsValidTopLevel()) return {};
2681
605
    return tl_node;
2682
606
}
std::optional<miniscript::Node<XOnlyPubKey>> miniscript::internal::DecodeScript<XOnlyPubKey, TapSatisfier, __gnu_cxx::__normal_iterator<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>*, std::vector<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>, std::allocator<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>>>>>(__gnu_cxx::__normal_iterator<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>*, std::vector<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>, std::allocator<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>>>>&, __gnu_cxx::__normal_iterator<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>*, std::vector<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>, std::allocator<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>>>>, TapSatisfier const&)
Line
Count
Source
2299
4.32k
{
2300
    // The two integers are used to hold state for thresh()
2301
4.32k
    std::vector<std::tuple<DecodeContext, int64_t, int64_t>> to_parse;
2302
4.32k
    std::vector<Node<Key>> constructed;
2303
2304
    // This is the top level, so we assume the type is B
2305
    // (in particular, disallowing top level W expressions)
2306
4.32k
    to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2307
2308
3.98M
    while (!to_parse.empty()) {
2309
        // Exit early if the Miniscript is not going to be valid.
2310
3.98M
        if (!constructed.empty() && !constructed.back().IsValid()) return {};
2311
2312
        // Get the current context we are decoding within
2313
3.98M
        auto [cur_context, n, k] = to_parse.back();
2314
3.98M
        to_parse.pop_back();
2315
2316
3.98M
        switch(cur_context) {
2317
1.98M
        case DecodeContext::SINGLE_BKV_EXPR: {
2318
1.98M
            if (in >= last) return {};
2319
2320
            // Constants
2321
1.98M
            if (in[0].first == OP_1) {
2322
0
                ++in;
2323
0
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1);
2324
0
                break;
2325
0
            }
2326
1.98M
            if (in[0].first == OP_0) {
2327
0
                ++in;
2328
0
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
2329
0
                break;
2330
0
            }
2331
            // Public keys
2332
1.98M
            if (in[0].second.size() == 33 || in[0].second.size() == 32) {
2333
3.37k
                auto key = ctx.FromPKBytes(in[0].second.begin(), in[0].second.end());
2334
3.37k
                if (!key) return {};
2335
3.37k
                ++in;
2336
3.37k
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_K, Vector(std::move(*key)));
2337
3.37k
                break;
2338
3.37k
            }
2339
1.98M
            if (last - in >= 5 && in[0].first == OP_VERIFY && in[1].first == OP_EQUAL && in[3].first == OP_HASH160 && in[4].first == OP_DUP && in[2].second.size() == 20) {
2340
336
                auto key = ctx.FromPKHBytes(in[2].second.begin(), in[2].second.end());
2341
336
                if (!key) return {};
2342
336
                in += 5;
2343
336
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_H, Vector(std::move(*key)));
2344
336
                break;
2345
336
            }
2346
            // Time locks
2347
1.98M
            std::optional<int64_t> num;
2348
1.98M
            if (last - in >= 2 && in[0].first == OP_CHECKSEQUENCEVERIFY && (num = ParseScriptNumber(in[1]))) {
2349
51
                in += 2;
2350
51
                if (*num < 1 || *num > 0x7FFFFFFFL) return {};
2351
51
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num);
2352
51
                break;
2353
51
            }
2354
1.98M
            if (last - in >= 2 && in[0].first == OP_CHECKLOCKTIMEVERIFY && (num = ParseScriptNumber(in[1]))) {
2355
789
                in += 2;
2356
789
                if (num < 1 || num > 0x7FFFFFFFL) return {};
2357
789
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num);
2358
789
                break;
2359
789
            }
2360
            // Hashes
2361
1.98M
            if (last - in >= 7 && in[0].first == OP_EQUAL && in[3].first == OP_VERIFY && in[4].first == OP_EQUAL && (num = ParseScriptNumber(in[5])) && num == 32 && in[6].first == OP_SIZE) {
2362
12
                if (in[2].first == OP_SHA256 && in[1].second.size() == 32) {
2363
0
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, in[1].second);
2364
0
                    in += 7;
2365
0
                    break;
2366
12
                } else if (in[2].first == OP_RIPEMD160 && in[1].second.size() == 20) {
2367
0
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::RIPEMD160, in[1].second);
2368
0
                    in += 7;
2369
0
                    break;
2370
12
                } else if (in[2].first == OP_HASH256 && in[1].second.size() == 32) {
2371
12
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, in[1].second);
2372
12
                    in += 7;
2373
12
                    break;
2374
12
                } else if (in[2].first == OP_HASH160 && in[1].second.size() == 20) {
2375
0
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, in[1].second);
2376
0
                    in += 7;
2377
0
                    break;
2378
0
                }
2379
12
            }
2380
            // Multi
2381
1.98M
            if (last - in >= 3 && in[0].first == OP_CHECKMULTISIG) {
2382
0
                if (IsTapscript(ctx.MsContext())) return {};
2383
0
                std::vector<Key> keys;
2384
0
                const auto n = ParseScriptNumber(in[1]);
2385
0
                if (!n || last - in < 3 + *n) return {};
2386
0
                if (*n < 1 || *n > 20) return {};
2387
0
                for (int i = 0; i < *n; ++i) {
2388
0
                    if (in[2 + i].second.size() != 33) return {};
2389
0
                    auto key = ctx.FromPKBytes(in[2 + i].second.begin(), in[2 + i].second.end());
2390
0
                    if (!key) return {};
2391
0
                    keys.push_back(std::move(*key));
2392
0
                }
2393
0
                const auto k = ParseScriptNumber(in[2 + *n]);
2394
0
                if (!k || *k < 1 || *k > *n) return {};
2395
0
                in += 3 + *n;
2396
0
                std::reverse(keys.begin(), keys.end());
2397
0
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), *k);
2398
0
                break;
2399
0
            }
2400
            // Tapscript's equivalent of multi
2401
1.98M
            if (last - in >= 4 && in[0].first == OP_NUMEQUAL) {
2402
784
                if (!IsTapscript(ctx.MsContext())) return {};
2403
                // The necessary threshold of signatures.
2404
784
                const auto k = ParseScriptNumber(in[1]);
2405
784
                if (!k) return {};
2406
784
                if (*k < 1 || *k > MAX_PUBKEYS_PER_MULTI_A) return {};
2407
784
                if (last - in < 2 + *k * 2) return {};
2408
784
                std::vector<Key> keys;
2409
784
                keys.reserve(*k);
2410
                // Walk through the expected (pubkey, CHECKSIG[ADD]) pairs.
2411
89.5k
                for (int pos = 2;; pos += 2) {
2412
89.5k
                    if (last - in < pos + 2) return {};
2413
                    // Make sure it's indeed an x-only pubkey and a CHECKSIG[ADD], then parse the key.
2414
89.5k
                    if (in[pos].first != OP_CHECKSIGADD && in[pos].first != OP_CHECKSIG) return {};
2415
89.5k
                    if (in[pos + 1].second.size() != 32) return {};
2416
89.5k
                    auto key = ctx.FromPKBytes(in[pos + 1].second.begin(), in[pos + 1].second.end());
2417
89.5k
                    if (!key) return {};
2418
89.5k
                    keys.push_back(std::move(*key));
2419
                    // Make sure early we don't parse an arbitrary large expression.
2420
89.5k
                    if (keys.size() > MAX_PUBKEYS_PER_MULTI_A) return {};
2421
                    // OP_CHECKSIG means it was the last one to parse.
2422
89.5k
                    if (in[pos].first == OP_CHECKSIG) break;
2423
89.5k
                }
2424
784
                if (keys.size() < (size_t)*k) return {};
2425
784
                in += 2 + keys.size() * 2;
2426
784
                std::reverse(keys.begin(), keys.end());
2427
784
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), *k);
2428
784
                break;
2429
784
            }
2430
            /** In the following wrappers, we only need to push SINGLE_BKV_EXPR rather
2431
             * than BKV_EXPR, because and_v commutes with these wrappers. For example,
2432
             * c:and_v(X,Y) produces the same script as and_v(X,c:Y). */
2433
            // c: wrapper
2434
1.98M
            if (in[0].first == OP_CHECKSIG) {
2435
3.70k
                ++in;
2436
3.70k
                to_parse.emplace_back(DecodeContext::CHECK, -1, -1);
2437
3.70k
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2438
3.70k
                break;
2439
3.70k
            }
2440
            // v: wrapper
2441
1.97M
            if (in[0].first == OP_VERIFY) {
2442
886
                ++in;
2443
886
                to_parse.emplace_back(DecodeContext::VERIFY, -1, -1);
2444
886
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2445
886
                break;
2446
886
            }
2447
            // n: wrapper
2448
1.97M
            if (in[0].first == OP_0NOTEQUAL) {
2449
1.97M
                ++in;
2450
1.97M
                to_parse.emplace_back(DecodeContext::ZERO_NOTEQUAL, -1, -1);
2451
1.97M
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2452
1.97M
                break;
2453
1.97M
            }
2454
            // Thresh
2455
120
            if (last - in >= 3 && in[0].first == OP_EQUAL && (num = ParseScriptNumber(in[1]))) {
2456
22
                if (*num < 1) return {};
2457
22
                in += 2;
2458
22
                to_parse.emplace_back(DecodeContext::THRESH_W, 0, *num);
2459
22
                break;
2460
22
            }
2461
            // OP_ENDIF can be WRAP_J, WRAP_D, ANDOR, OR_C, OR_D, or OR_I
2462
98
            if (in[0].first == OP_ENDIF) {
2463
6
                ++in;
2464
6
                to_parse.emplace_back(DecodeContext::ENDIF, -1, -1);
2465
6
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2466
6
                break;
2467
6
            }
2468
            /** In and_b and or_b nodes, we only look for SINGLE_BKV_EXPR, because
2469
             * or_b(and_v(X,Y),Z) has script [X] [Y] [Z] OP_BOOLOR, the same as
2470
             * and_v(X,or_b(Y,Z)). In this example, the former of these is invalid as
2471
             * miniscript, while the latter is valid. So we leave the and_v "outside"
2472
             * while decoding. */
2473
            // and_b
2474
92
            if (in[0].first == OP_BOOLAND) {
2475
64
                ++in;
2476
64
                to_parse.emplace_back(DecodeContext::AND_B, -1, -1);
2477
64
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2478
64
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2479
64
                break;
2480
64
            }
2481
            // or_b
2482
28
            if (in[0].first == OP_BOOLOR) {
2483
28
                ++in;
2484
28
                to_parse.emplace_back(DecodeContext::OR_B, -1, -1);
2485
28
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2486
28
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2487
28
                break;
2488
28
            }
2489
            // Unrecognised expression
2490
0
            return {};
2491
28
        }
2492
5.35k
        case DecodeContext::BKV_EXPR: {
2493
5.35k
            to_parse.emplace_back(DecodeContext::MAYBE_AND_V, -1, -1);
2494
5.35k
            to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2495
5.35k
            break;
2496
28
        }
2497
136
        case DecodeContext::W_EXPR: {
2498
            // a: wrapper
2499
136
            if (in >= last) return {};
2500
136
            if (in[0].first == OP_FROMALTSTACK) {
2501
86
                ++in;
2502
86
                to_parse.emplace_back(DecodeContext::ALT, -1, -1);
2503
86
            } else {
2504
50
                to_parse.emplace_back(DecodeContext::SWAP, -1, -1);
2505
50
            }
2506
136
            to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2507
136
            break;
2508
136
        }
2509
5.35k
        case DecodeContext::MAYBE_AND_V: {
2510
            // If we reach a potential AND_V top-level, check if the next part of the script could be another AND_V child
2511
            // These op-codes cannot end any well-formed miniscript so cannot be used in an and_v node.
2512
5.35k
            if (in < last && in[0].first != OP_IF && in[0].first != OP_ELSE && in[0].first != OP_NOTIF && in[0].first != OP_TOALTSTACK && in[0].first != OP_SWAP) {
2513
880
                to_parse.emplace_back(DecodeContext::AND_V, -1, -1);
2514
                // BKV_EXPR can contain more AND_V nodes
2515
880
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2516
880
            }
2517
5.35k
            break;
2518
136
        }
2519
50
        case DecodeContext::SWAP: {
2520
50
            if (in >= last || in[0].first != OP_SWAP || constructed.empty()) return {};
2521
50
            ++in;
2522
50
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S, Vector(std::move(constructed.back()))};
2523
50
            break;
2524
50
        }
2525
86
        case DecodeContext::ALT: {
2526
86
            if (in >= last || in[0].first != OP_TOALTSTACK || constructed.empty()) return {};
2527
86
            ++in;
2528
86
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A, Vector(std::move(constructed.back()))};
2529
86
            break;
2530
86
        }
2531
3.70k
        case DecodeContext::CHECK: {
2532
3.70k
            if (constructed.empty()) return {};
2533
3.70k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(std::move(constructed.back()))};
2534
3.70k
            break;
2535
3.70k
        }
2536
6
        case DecodeContext::DUP_IF: {
2537
6
            if (constructed.empty()) return {};
2538
6
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D, Vector(std::move(constructed.back()))};
2539
6
            break;
2540
6
        }
2541
886
        case DecodeContext::VERIFY: {
2542
886
            if (constructed.empty()) return {};
2543
886
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V, Vector(std::move(constructed.back()))};
2544
886
            break;
2545
886
        }
2546
0
        case DecodeContext::NON_ZERO: {
2547
0
            if (constructed.empty()) return {};
2548
0
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J, Vector(std::move(constructed.back()))};
2549
0
            break;
2550
0
        }
2551
1.97M
        case DecodeContext::ZERO_NOTEQUAL: {
2552
1.97M
            if (constructed.empty()) return {};
2553
1.97M
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N, Vector(std::move(constructed.back()))};
2554
1.97M
            break;
2555
1.97M
        }
2556
880
        case DecodeContext::AND_V: {
2557
880
            if (constructed.size() < 2) return {};
2558
880
            BuildBack(ctx.MsContext(), Fragment::AND_V, constructed, /*reverse=*/true);
2559
880
            break;
2560
880
        }
2561
64
        case DecodeContext::AND_B: {
2562
64
            if (constructed.size() < 2) return {};
2563
64
            BuildBack(ctx.MsContext(), Fragment::AND_B, constructed, /*reverse=*/true);
2564
64
            break;
2565
64
        }
2566
28
        case DecodeContext::OR_B: {
2567
28
            if (constructed.size() < 2) return {};
2568
28
            BuildBack(ctx.MsContext(), Fragment::OR_B, constructed, /*reverse=*/true);
2569
28
            break;
2570
28
        }
2571
0
        case DecodeContext::OR_C: {
2572
0
            if (constructed.size() < 2) return {};
2573
0
            BuildBack(ctx.MsContext(), Fragment::OR_C, constructed, /*reverse=*/true);
2574
0
            break;
2575
0
        }
2576
0
        case DecodeContext::OR_D: {
2577
0
            if (constructed.size() < 2) return {};
2578
0
            BuildBack(ctx.MsContext(), Fragment::OR_D, constructed, /*reverse=*/true);
2579
0
            break;
2580
0
        }
2581
0
        case DecodeContext::ANDOR: {
2582
0
            if (constructed.size() < 3) return {};
2583
0
            Node left{std::move(constructed.back())};
2584
0
            constructed.pop_back();
2585
0
            Node right{std::move(constructed.back())};
2586
0
            constructed.pop_back();
2587
0
            Node mid{std::move(constructed.back())};
2588
0
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR, Vector(std::move(left), std::move(mid), std::move(right))};
2589
0
            break;
2590
0
        }
2591
66
        case DecodeContext::THRESH_W: {
2592
66
            if (in >= last) return {};
2593
66
            if (in[0].first == OP_ADD) {
2594
44
                ++in;
2595
44
                to_parse.emplace_back(DecodeContext::THRESH_W, n+1, k);
2596
44
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2597
44
            } else {
2598
22
                to_parse.emplace_back(DecodeContext::THRESH_E, n+1, k);
2599
                // All children of thresh have type modifier d, so cannot be and_v
2600
22
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2601
22
            }
2602
66
            break;
2603
66
        }
2604
22
        case DecodeContext::THRESH_E: {
2605
22
            if (k < 1 || k > n || constructed.size() < static_cast<size_t>(n)) return {};
2606
22
            std::vector<Node<Key>> subs;
2607
88
            for (int i = 0; i < n; ++i) {
2608
66
                Node sub{std::move(constructed.back())};
2609
66
                constructed.pop_back();
2610
66
                subs.push_back(std::move(sub));
2611
66
            }
2612
22
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs), k);
2613
22
            break;
2614
22
        }
2615
6
        case DecodeContext::ENDIF: {
2616
6
            if (in >= last) return {};
2617
2618
            // could be andor or or_i
2619
6
            if (in[0].first == OP_ELSE) {
2620
0
                ++in;
2621
0
                to_parse.emplace_back(DecodeContext::ENDIF_ELSE, -1, -1);
2622
0
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2623
0
            }
2624
            // could be j: or d: wrapper
2625
6
            else if (in[0].first == OP_IF) {
2626
6
                if (last - in >= 2 && in[1].first == OP_DUP) {
2627
6
                    in += 2;
2628
6
                    to_parse.emplace_back(DecodeContext::DUP_IF, -1, -1);
2629
6
                } else if (last - in >= 3 && in[1].first == OP_0NOTEQUAL && in[2].first == OP_SIZE) {
2630
0
                    in += 3;
2631
0
                    to_parse.emplace_back(DecodeContext::NON_ZERO, -1, -1);
2632
0
                }
2633
0
                else {
2634
0
                    return {};
2635
0
                }
2636
            // could be or_c or or_d
2637
6
            } else if (in[0].first == OP_NOTIF) {
2638
0
                ++in;
2639
0
                to_parse.emplace_back(DecodeContext::ENDIF_NOTIF, -1, -1);
2640
0
            }
2641
0
            else {
2642
0
                return {};
2643
0
            }
2644
6
            break;
2645
6
        }
2646
6
        case DecodeContext::ENDIF_NOTIF: {
2647
0
            if (in >= last) return {};
2648
0
            if (in[0].first == OP_IFDUP) {
2649
0
                ++in;
2650
0
                to_parse.emplace_back(DecodeContext::OR_D, -1, -1);
2651
0
            } else {
2652
0
                to_parse.emplace_back(DecodeContext::OR_C, -1, -1);
2653
0
            }
2654
            // or_c and or_d both require X to have type modifier d so, can't contain and_v
2655
0
            to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2656
0
            break;
2657
0
        }
2658
0
        case DecodeContext::ENDIF_ELSE: {
2659
0
            if (in >= last) return {};
2660
0
            if (in[0].first == OP_IF) {
2661
0
                ++in;
2662
0
                BuildBack(ctx.MsContext(), Fragment::OR_I, constructed, /*reverse=*/true);
2663
0
            } else if (in[0].first == OP_NOTIF) {
2664
0
                ++in;
2665
0
                to_parse.emplace_back(DecodeContext::ANDOR, -1, -1);
2666
                // andor requires X to have type modifier d, so it can't be and_v
2667
0
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2668
0
            } else {
2669
0
                return {};
2670
0
            }
2671
0
            break;
2672
0
        }
2673
3.98M
        }
2674
3.98M
    }
2675
4.32k
    if (constructed.size() != 1) return {};
2676
4.32k
    Node tl_node{std::move(constructed.front())};
2677
4.32k
    tl_node.DuplicateKeyCheck(ctx);
2678
    // Note that due to how ComputeType works (only assign the type to the node if the
2679
    // subs' types are valid) this would fail if any node of tree is badly typed.
2680
4.32k
    if (!tl_node.IsValidTopLevel()) return {};
2681
4.32k
    return tl_node;
2682
4.32k
}
std::optional<miniscript::Node<CPubKey>> miniscript::internal::DecodeScript<CPubKey, WshSatisfier, __gnu_cxx::__normal_iterator<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>*, std::vector<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>, std::allocator<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>>>>>(__gnu_cxx::__normal_iterator<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>*, std::vector<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>, std::allocator<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>>>>&, __gnu_cxx::__normal_iterator<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>*, std::vector<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>, std::allocator<std::pair<opcodetype, std::vector<unsigned char, std::allocator<unsigned char>>>>>>, WshSatisfier const&)
Line
Count
Source
2299
218
{
2300
    // The two integers are used to hold state for thresh()
2301
218
    std::vector<std::tuple<DecodeContext, int64_t, int64_t>> to_parse;
2302
218
    std::vector<Node<Key>> constructed;
2303
2304
    // This is the top level, so we assume the type is B
2305
    // (in particular, disallowing top level W expressions)
2306
218
    to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2307
2308
8.98k
    while (!to_parse.empty()) {
2309
        // Exit early if the Miniscript is not going to be valid.
2310
8.76k
        if (!constructed.empty() && !constructed.back().IsValid()) return {};
2311
2312
        // Get the current context we are decoding within
2313
8.76k
        auto [cur_context, n, k] = to_parse.back();
2314
8.76k
        to_parse.pop_back();
2315
2316
8.76k
        switch(cur_context) {
2317
2.51k
        case DecodeContext::SINGLE_BKV_EXPR: {
2318
2.51k
            if (in >= last) return {};
2319
2320
            // Constants
2321
2.51k
            if (in[0].first == OP_1) {
2322
0
                ++in;
2323
0
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1);
2324
0
                break;
2325
0
            }
2326
2.51k
            if (in[0].first == OP_0) {
2327
243
                ++in;
2328
243
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
2329
243
                break;
2330
243
            }
2331
            // Public keys
2332
2.27k
            if (in[0].second.size() == 33 || in[0].second.size() == 32) {
2333
460
                auto key = ctx.FromPKBytes(in[0].second.begin(), in[0].second.end());
2334
460
                if (!key) return {};
2335
459
                ++in;
2336
459
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_K, Vector(std::move(*key)));
2337
459
                break;
2338
460
            }
2339
1.81k
            if (last - in >= 5 && in[0].first == OP_VERIFY && in[1].first == OP_EQUAL && in[3].first == OP_HASH160 && in[4].first == OP_DUP && in[2].second.size() == 20) {
2340
70
                auto key = ctx.FromPKHBytes(in[2].second.begin(), in[2].second.end());
2341
70
                if (!key) return {};
2342
69
                in += 5;
2343
69
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_H, Vector(std::move(*key)));
2344
69
                break;
2345
70
            }
2346
            // Time locks
2347
1.74k
            std::optional<int64_t> num;
2348
1.74k
            if (last - in >= 2 && in[0].first == OP_CHECKSEQUENCEVERIFY && (num = ParseScriptNumber(in[1]))) {
2349
58
                in += 2;
2350
58
                if (*num < 1 || *num > 0x7FFFFFFFL) return {};
2351
58
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num);
2352
58
                break;
2353
58
            }
2354
1.68k
            if (last - in >= 2 && in[0].first == OP_CHECKLOCKTIMEVERIFY && (num = ParseScriptNumber(in[1]))) {
2355
244
                in += 2;
2356
244
                if (num < 1 || num > 0x7FFFFFFFL) return {};
2357
244
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num);
2358
244
                break;
2359
244
            }
2360
            // Hashes
2361
1.43k
            if (last - in >= 7 && in[0].first == OP_EQUAL && in[3].first == OP_VERIFY && in[4].first == OP_EQUAL && (num = ParseScriptNumber(in[5])) && num == 32 && in[6].first == OP_SIZE) {
2362
53
                if (in[2].first == OP_SHA256 && in[1].second.size() == 32) {
2363
17
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, in[1].second);
2364
17
                    in += 7;
2365
17
                    break;
2366
36
                } else if (in[2].first == OP_RIPEMD160 && in[1].second.size() == 20) {
2367
12
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::RIPEMD160, in[1].second);
2368
12
                    in += 7;
2369
12
                    break;
2370
24
                } else if (in[2].first == OP_HASH256 && in[1].second.size() == 32) {
2371
12
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, in[1].second);
2372
12
                    in += 7;
2373
12
                    break;
2374
12
                } else if (in[2].first == OP_HASH160 && in[1].second.size() == 20) {
2375
12
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, in[1].second);
2376
12
                    in += 7;
2377
12
                    break;
2378
12
                }
2379
53
            }
2380
            // Multi
2381
1.38k
            if (last - in >= 3 && in[0].first == OP_CHECKMULTISIG) {
2382
24
                if (IsTapscript(ctx.MsContext())) return {};
2383
24
                std::vector<Key> keys;
2384
24
                const auto n = ParseScriptNumber(in[1]);
2385
24
                if (!n || last - in < 3 + *n) return {};
2386
24
                if (*n < 1 || *n > 20) return {};
2387
72
                for (int i = 0; i < *n; ++i) {
2388
48
                    if (in[2 + i].second.size() != 33) return {};
2389
48
                    auto key = ctx.FromPKBytes(in[2 + i].second.begin(), in[2 + i].second.end());
2390
48
                    if (!key) return {};
2391
48
                    keys.push_back(std::move(*key));
2392
48
                }
2393
24
                const auto k = ParseScriptNumber(in[2 + *n]);
2394
24
                if (!k || *k < 1 || *k > *n) return {};
2395
24
                in += 3 + *n;
2396
24
                std::reverse(keys.begin(), keys.end());
2397
24
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), *k);
2398
24
                break;
2399
24
            }
2400
            // Tapscript's equivalent of multi
2401
1.36k
            if (last - in >= 4 && in[0].first == OP_NUMEQUAL) {
2402
0
                if (!IsTapscript(ctx.MsContext())) return {};
2403
                // The necessary threshold of signatures.
2404
0
                const auto k = ParseScriptNumber(in[1]);
2405
0
                if (!k) return {};
2406
0
                if (*k < 1 || *k > MAX_PUBKEYS_PER_MULTI_A) return {};
2407
0
                if (last - in < 2 + *k * 2) return {};
2408
0
                std::vector<Key> keys;
2409
0
                keys.reserve(*k);
2410
                // Walk through the expected (pubkey, CHECKSIG[ADD]) pairs.
2411
0
                for (int pos = 2;; pos += 2) {
2412
0
                    if (last - in < pos + 2) return {};
2413
                    // Make sure it's indeed an x-only pubkey and a CHECKSIG[ADD], then parse the key.
2414
0
                    if (in[pos].first != OP_CHECKSIGADD && in[pos].first != OP_CHECKSIG) return {};
2415
0
                    if (in[pos + 1].second.size() != 32) return {};
2416
0
                    auto key = ctx.FromPKBytes(in[pos + 1].second.begin(), in[pos + 1].second.end());
2417
0
                    if (!key) return {};
2418
0
                    keys.push_back(std::move(*key));
2419
                    // Make sure early we don't parse an arbitrary large expression.
2420
0
                    if (keys.size() > MAX_PUBKEYS_PER_MULTI_A) return {};
2421
                    // OP_CHECKSIG means it was the last one to parse.
2422
0
                    if (in[pos].first == OP_CHECKSIG) break;
2423
0
                }
2424
0
                if (keys.size() < (size_t)*k) return {};
2425
0
                in += 2 + keys.size() * 2;
2426
0
                std::reverse(keys.begin(), keys.end());
2427
0
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), *k);
2428
0
                break;
2429
0
            }
2430
            /** In the following wrappers, we only need to push SINGLE_BKV_EXPR rather
2431
             * than BKV_EXPR, because and_v commutes with these wrappers. For example,
2432
             * c:and_v(X,Y) produces the same script as and_v(X,c:Y). */
2433
            // c: wrapper
2434
1.36k
            if (in[0].first == OP_CHECKSIG) {
2435
526
                ++in;
2436
526
                to_parse.emplace_back(DecodeContext::CHECK, -1, -1);
2437
526
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2438
526
                break;
2439
526
            }
2440
            // v: wrapper
2441
836
            if (in[0].first == OP_VERIFY) {
2442
125
                ++in;
2443
125
                to_parse.emplace_back(DecodeContext::VERIFY, -1, -1);
2444
125
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2445
125
                break;
2446
125
            }
2447
            // n: wrapper
2448
711
            if (in[0].first == OP_0NOTEQUAL) {
2449
266
                ++in;
2450
266
                to_parse.emplace_back(DecodeContext::ZERO_NOTEQUAL, -1, -1);
2451
266
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2452
266
                break;
2453
266
            }
2454
            // Thresh
2455
445
            if (last - in >= 3 && in[0].first == OP_EQUAL && (num = ParseScriptNumber(in[1]))) {
2456
112
                if (*num < 1) return {};
2457
112
                in += 2;
2458
112
                to_parse.emplace_back(DecodeContext::THRESH_W, 0, *num);
2459
112
                break;
2460
112
            }
2461
            // OP_ENDIF can be WRAP_J, WRAP_D, ANDOR, OR_C, OR_D, or OR_I
2462
333
            if (in[0].first == OP_ENDIF) {
2463
296
                ++in;
2464
296
                to_parse.emplace_back(DecodeContext::ENDIF, -1, -1);
2465
296
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2466
296
                break;
2467
296
            }
2468
            /** In and_b and or_b nodes, we only look for SINGLE_BKV_EXPR, because
2469
             * or_b(and_v(X,Y),Z) has script [X] [Y] [Z] OP_BOOLOR, the same as
2470
             * and_v(X,or_b(Y,Z)). In this example, the former of these is invalid as
2471
             * miniscript, while the latter is valid. So we leave the and_v "outside"
2472
             * while decoding. */
2473
            // and_b
2474
37
            if (in[0].first == OP_BOOLAND) {
2475
36
                ++in;
2476
36
                to_parse.emplace_back(DecodeContext::AND_B, -1, -1);
2477
36
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2478
36
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2479
36
                break;
2480
36
            }
2481
            // or_b
2482
1
            if (in[0].first == OP_BOOLOR) {
2483
0
                ++in;
2484
0
                to_parse.emplace_back(DecodeContext::OR_B, -1, -1);
2485
0
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2486
0
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2487
0
                break;
2488
0
            }
2489
            // Unrecognised expression
2490
1
            return {};
2491
1
        }
2492
1.40k
        case DecodeContext::BKV_EXPR: {
2493
1.40k
            to_parse.emplace_back(DecodeContext::MAYBE_AND_V, -1, -1);
2494
1.40k
            to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2495
1.40k
            break;
2496
1
        }
2497
522
        case DecodeContext::W_EXPR: {
2498
            // a: wrapper
2499
522
            if (in >= last) return {};
2500
522
            if (in[0].first == OP_FROMALTSTACK) {
2501
75
                ++in;
2502
75
                to_parse.emplace_back(DecodeContext::ALT, -1, -1);
2503
447
            } else {
2504
447
                to_parse.emplace_back(DecodeContext::SWAP, -1, -1);
2505
447
            }
2506
522
            to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2507
522
            break;
2508
522
        }
2509
1.40k
        case DecodeContext::MAYBE_AND_V: {
2510
            // If we reach a potential AND_V top-level, check if the next part of the script could be another AND_V child
2511
            // These op-codes cannot end any well-formed miniscript so cannot be used in an and_v node.
2512
1.40k
            if (in < last && in[0].first != OP_IF && in[0].first != OP_ELSE && in[0].first != OP_NOTIF && in[0].first != OP_TOALTSTACK && in[0].first != OP_SWAP) {
2513
102
                to_parse.emplace_back(DecodeContext::AND_V, -1, -1);
2514
                // BKV_EXPR can contain more AND_V nodes
2515
102
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2516
102
            }
2517
1.40k
            break;
2518
522
        }
2519
447
        case DecodeContext::SWAP: {
2520
447
            if (in >= last || in[0].first != OP_SWAP || constructed.empty()) return {};
2521
447
            ++in;
2522
447
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S, Vector(std::move(constructed.back()))};
2523
447
            break;
2524
447
        }
2525
75
        case DecodeContext::ALT: {
2526
75
            if (in >= last || in[0].first != OP_TOALTSTACK || constructed.empty()) return {};
2527
75
            ++in;
2528
75
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A, Vector(std::move(constructed.back()))};
2529
75
            break;
2530
75
        }
2531
525
        case DecodeContext::CHECK: {
2532
525
            if (constructed.empty()) return {};
2533
525
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(std::move(constructed.back()))};
2534
525
            break;
2535
525
        }
2536
23
        case DecodeContext::DUP_IF: {
2537
23
            if (constructed.empty()) return {};
2538
23
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D, Vector(std::move(constructed.back()))};
2539
23
            break;
2540
23
        }
2541
125
        case DecodeContext::VERIFY: {
2542
125
            if (constructed.empty()) return {};
2543
125
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V, Vector(std::move(constructed.back()))};
2544
125
            break;
2545
125
        }
2546
0
        case DecodeContext::NON_ZERO: {
2547
0
            if (constructed.empty()) return {};
2548
0
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J, Vector(std::move(constructed.back()))};
2549
0
            break;
2550
0
        }
2551
266
        case DecodeContext::ZERO_NOTEQUAL: {
2552
266
            if (constructed.empty()) return {};
2553
266
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N, Vector(std::move(constructed.back()))};
2554
266
            break;
2555
266
        }
2556
102
        case DecodeContext::AND_V: {
2557
102
            if (constructed.size() < 2) return {};
2558
102
            BuildBack(ctx.MsContext(), Fragment::AND_V, constructed, /*reverse=*/true);
2559
102
            break;
2560
102
        }
2561
36
        case DecodeContext::AND_B: {
2562
36
            if (constructed.size() < 2) return {};
2563
36
            BuildBack(ctx.MsContext(), Fragment::AND_B, constructed, /*reverse=*/true);
2564
36
            break;
2565
36
        }
2566
0
        case DecodeContext::OR_B: {
2567
0
            if (constructed.size() < 2) return {};
2568
0
            BuildBack(ctx.MsContext(), Fragment::OR_B, constructed, /*reverse=*/true);
2569
0
            break;
2570
0
        }
2571
0
        case DecodeContext::OR_C: {
2572
0
            if (constructed.size() < 2) return {};
2573
0
            BuildBack(ctx.MsContext(), Fragment::OR_C, constructed, /*reverse=*/true);
2574
0
            break;
2575
0
        }
2576
5
        case DecodeContext::OR_D: {
2577
5
            if (constructed.size() < 2) return {};
2578
5
            BuildBack(ctx.MsContext(), Fragment::OR_D, constructed, /*reverse=*/true);
2579
5
            break;
2580
5
        }
2581
38
        case DecodeContext::ANDOR: {
2582
38
            if (constructed.size() < 3) return {};
2583
38
            Node left{std::move(constructed.back())};
2584
38
            constructed.pop_back();
2585
38
            Node right{std::move(constructed.back())};
2586
38
            constructed.pop_back();
2587
38
            Node mid{std::move(constructed.back())};
2588
38
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR, Vector(std::move(left), std::move(mid), std::move(right))};
2589
38
            break;
2590
38
        }
2591
598
        case DecodeContext::THRESH_W: {
2592
598
            if (in >= last) return {};
2593
598
            if (in[0].first == OP_ADD) {
2594
486
                ++in;
2595
486
                to_parse.emplace_back(DecodeContext::THRESH_W, n+1, k);
2596
486
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2597
486
            } else {
2598
112
                to_parse.emplace_back(DecodeContext::THRESH_E, n+1, k);
2599
                // All children of thresh have type modifier d, so cannot be and_v
2600
112
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2601
112
            }
2602
598
            break;
2603
598
        }
2604
112
        case DecodeContext::THRESH_E: {
2605
112
            if (k < 1 || k > n || constructed.size() < static_cast<size_t>(n)) return {};
2606
112
            std::vector<Node<Key>> subs;
2607
710
            for (int i = 0; i < n; ++i) {
2608
598
                Node sub{std::move(constructed.back())};
2609
598
                constructed.pop_back();
2610
598
                subs.push_back(std::move(sub));
2611
598
            }
2612
112
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs), k);
2613
112
            break;
2614
112
        }
2615
296
        case DecodeContext::ENDIF: {
2616
296
            if (in >= last) return {};
2617
2618
            // could be andor or or_i
2619
296
            if (in[0].first == OP_ELSE) {
2620
268
                ++in;
2621
268
                to_parse.emplace_back(DecodeContext::ENDIF_ELSE, -1, -1);
2622
268
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2623
268
            }
2624
            // could be j: or d: wrapper
2625
28
            else if (in[0].first == OP_IF) {
2626
23
                if (last - in >= 2 && in[1].first == OP_DUP) {
2627
23
                    in += 2;
2628
23
                    to_parse.emplace_back(DecodeContext::DUP_IF, -1, -1);
2629
23
                } else if (last - in >= 3 && in[1].first == OP_0NOTEQUAL && in[2].first == OP_SIZE) {
2630
0
                    in += 3;
2631
0
                    to_parse.emplace_back(DecodeContext::NON_ZERO, -1, -1);
2632
0
                }
2633
0
                else {
2634
0
                    return {};
2635
0
                }
2636
            // could be or_c or or_d
2637
23
            } else if (in[0].first == OP_NOTIF) {
2638
5
                ++in;
2639
5
                to_parse.emplace_back(DecodeContext::ENDIF_NOTIF, -1, -1);
2640
5
            }
2641
0
            else {
2642
0
                return {};
2643
0
            }
2644
296
            break;
2645
296
        }
2646
296
        case DecodeContext::ENDIF_NOTIF: {
2647
5
            if (in >= last) return {};
2648
5
            if (in[0].first == OP_IFDUP) {
2649
5
                ++in;
2650
5
                to_parse.emplace_back(DecodeContext::OR_D, -1, -1);
2651
5
            } else {
2652
0
                to_parse.emplace_back(DecodeContext::OR_C, -1, -1);
2653
0
            }
2654
            // or_c and or_d both require X to have type modifier d so, can't contain and_v
2655
5
            to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2656
5
            break;
2657
5
        }
2658
268
        case DecodeContext::ENDIF_ELSE: {
2659
268
            if (in >= last) return {};
2660
268
            if (in[0].first == OP_IF) {
2661
230
                ++in;
2662
230
                BuildBack(ctx.MsContext(), Fragment::OR_I, constructed, /*reverse=*/true);
2663
230
            } else if (in[0].first == OP_NOTIF) {
2664
38
                ++in;
2665
38
                to_parse.emplace_back(DecodeContext::ANDOR, -1, -1);
2666
                // andor requires X to have type modifier d, so it can't be and_v
2667
38
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2668
38
            } else {
2669
0
                return {};
2670
0
            }
2671
268
            break;
2672
268
        }
2673
8.76k
        }
2674
8.76k
    }
2675
215
    if (constructed.size() != 1) return {};
2676
215
    Node tl_node{std::move(constructed.front())};
2677
215
    tl_node.DuplicateKeyCheck(ctx);
2678
    // Note that due to how ComputeType works (only assign the type to the node if the
2679
    // subs' types are valid) this would fail if any node of tree is badly typed.
2680
215
    if (!tl_node.IsValidTopLevel()) return {};
2681
215
    return tl_node;
2682
215
}
2683
2684
} // namespace internal
2685
2686
template <typename Ctx>
2687
inline std::optional<Node<typename Ctx::Key>> FromString(const std::string& str, const Ctx& ctx)
2688
760
{
2689
760
    return internal::Parse<typename Ctx::Key>(str, ctx);
2690
760
}
miniscript_tests.cpp:std::optional<miniscript::Node<(anonymous namespace)::KeyConverter::Key>> miniscript::FromString<(anonymous namespace)::KeyConverter>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&, (anonymous namespace)::KeyConverter const&)
Line
Count
Source
2688
220
{
2689
220
    return internal::Parse<typename Ctx::Key>(str, ctx);
2690
220
}
descriptor.cpp:std::optional<miniscript::Node<(anonymous namespace)::KeyParser::Key>> miniscript::FromString<(anonymous namespace)::KeyParser>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&, (anonymous namespace)::KeyParser const&)
Line
Count
Source
2688
540
{
2689
540
    return internal::Parse<typename Ctx::Key>(str, ctx);
2690
540
}
2691
2692
template <typename Ctx>
2693
inline std::optional<Node<typename Ctx::Key>> FromScript(const CScript& script, const Ctx& ctx)
2694
5.29k
{
2695
5.29k
    using namespace internal;
2696
    // A too large Script is necessarily invalid, don't bother parsing it.
2697
5.29k
    if (script.size() > MaxScriptSize(ctx.MsContext())) return {};
2698
5.29k
    auto decomposed = DecomposeScript(script);
2699
5.29k
    if (!decomposed) return {};
2700
5.29k
    auto it = decomposed->begin();
2701
5.29k
    auto ret = DecodeScript<typename Ctx::Key>(it, decomposed->end(), ctx);
2702
5.29k
    if (!ret) return {};
2703
5.27k
    if (it != decomposed->end()) return {};
2704
5.27k
    return ret;
2705
5.27k
}
miniscript_tests.cpp:std::optional<miniscript::Node<(anonymous namespace)::KeyConverter::Key>> miniscript::FromScript<(anonymous namespace)::KeyConverter>(CScript const&, (anonymous namespace)::KeyConverter const&)
Line
Count
Source
2694
132
{
2695
132
    using namespace internal;
2696
    // A too large Script is necessarily invalid, don't bother parsing it.
2697
132
    if (script.size() > MaxScriptSize(ctx.MsContext())) return {};
2698
132
    auto decomposed = DecomposeScript(script);
2699
132
    if (!decomposed) return {};
2700
128
    auto it = decomposed->begin();
2701
128
    auto ret = DecodeScript<typename Ctx::Key>(it, decomposed->end(), ctx);
2702
128
    if (!ret) return {};
2703
125
    if (it != decomposed->end()) return {};
2704
125
    return ret;
2705
125
}
descriptor.cpp:std::optional<miniscript::Node<(anonymous namespace)::KeyParser::Key>> miniscript::FromScript<(anonymous namespace)::KeyParser>(CScript const&, (anonymous namespace)::KeyParser const&)
Line
Count
Source
2694
618
{
2695
618
    using namespace internal;
2696
    // A too large Script is necessarily invalid, don't bother parsing it.
2697
618
    if (script.size() > MaxScriptSize(ctx.MsContext())) return {};
2698
618
    auto decomposed = DecomposeScript(script);
2699
618
    if (!decomposed) return {};
2700
618
    auto it = decomposed->begin();
2701
618
    auto ret = DecodeScript<typename Ctx::Key>(it, decomposed->end(), ctx);
2702
618
    if (!ret) return {};
2703
605
    if (it != decomposed->end()) return {};
2704
605
    return ret;
2705
605
}
std::optional<miniscript::Node<TapSatisfier::Key>> miniscript::FromScript<TapSatisfier>(CScript const&, TapSatisfier const&)
Line
Count
Source
2694
4.32k
{
2695
4.32k
    using namespace internal;
2696
    // A too large Script is necessarily invalid, don't bother parsing it.
2697
4.32k
    if (script.size() > MaxScriptSize(ctx.MsContext())) return {};
2698
4.32k
    auto decomposed = DecomposeScript(script);
2699
4.32k
    if (!decomposed) return {};
2700
4.32k
    auto it = decomposed->begin();
2701
4.32k
    auto ret = DecodeScript<typename Ctx::Key>(it, decomposed->end(), ctx);
2702
4.32k
    if (!ret) return {};
2703
4.32k
    if (it != decomposed->end()) return {};
2704
4.32k
    return ret;
2705
4.32k
}
std::optional<miniscript::Node<WshSatisfier::Key>> miniscript::FromScript<WshSatisfier>(CScript const&, WshSatisfier const&)
Line
Count
Source
2694
218
{
2695
218
    using namespace internal;
2696
    // A too large Script is necessarily invalid, don't bother parsing it.
2697
218
    if (script.size() > MaxScriptSize(ctx.MsContext())) return {};
2698
218
    auto decomposed = DecomposeScript(script);
2699
218
    if (!decomposed) return {};
2700
218
    auto it = decomposed->begin();
2701
218
    auto ret = DecodeScript<typename Ctx::Key>(it, decomposed->end(), ctx);
2702
218
    if (!ret) return {};
2703
215
    if (it != decomposed->end()) return {};
2704
215
    return ret;
2705
215
}
2706
2707
} // namespace miniscript
2708
2709
#endif // BITCOIN_SCRIPT_MINISCRIPT_H