Coverage Report

Created: 2026-05-30 09:47

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 <compare>
22
#include <concepts>
23
#include <cstdint>
24
#include <cstdlib>
25
#include <functional>
26
#include <memory>
27
#include <optional>
28
#include <set>
29
#include <span>
30
#include <stdexcept>
31
#include <string>
32
#include <string_view>
33
#include <tuple>
34
#include <utility>
35
#include <variant>
36
#include <vector>
37
38
namespace miniscript {
39
40
/** This type encapsulates the miniscript type system properties.
41
 *
42
 * Every miniscript expression is one of 4 basic types, and additionally has
43
 * a number of boolean type properties.
44
 *
45
 * The basic types are:
46
 * - "B" Base:
47
 *   - Takes its inputs from the top of the stack.
48
 *   - When satisfied, pushes a nonzero value of up to 4 bytes onto the stack.
49
 *   - When dissatisfied, pushes a 0 onto the stack.
50
 *   - This is used for most expressions, and required for the top level one.
51
 *   - For example: older(n) = <n> OP_CHECKSEQUENCEVERIFY.
52
 * - "V" Verify:
53
 *   - Takes its inputs from the top of the stack.
54
 *   - When satisfied, pushes nothing.
55
 *   - Cannot be dissatisfied.
56
 *   - This can be obtained by adding an OP_VERIFY to a B, modifying the last opcode
57
 *     of a B to its -VERIFY version (only for OP_CHECKSIG, OP_CHECKSIGVERIFY,
58
 *     OP_NUMEQUAL and OP_EQUAL), or by combining a V fragment under some conditions.
59
 *   - For example vc:pk_k(key) = <key> OP_CHECKSIGVERIFY
60
 * - "K" Key:
61
 *   - Takes its inputs from the top of the stack.
62
 *   - Becomes a B when followed by OP_CHECKSIG.
63
 *   - Always pushes a public key onto the stack, for which a signature is to be
64
 *     provided to satisfy the expression.
65
 *   - For example pk_h(key) = OP_DUP OP_HASH160 <Hash160(key)> OP_EQUALVERIFY
66
 * - "W" Wrapped:
67
 *   - Takes its input from one below the top of the stack.
68
 *   - When satisfied, pushes a nonzero value (like B) on top of the stack, or one below.
69
 *   - When dissatisfied, pushes 0 op top of the stack or one below.
70
 *   - Is always "OP_SWAP [B]" or "OP_TOALTSTACK [B] OP_FROMALTSTACK".
71
 *   - For example sc:pk_k(key) = OP_SWAP <key> OP_CHECKSIG
72
 *
73
 * There are type properties that help reasoning about correctness:
74
 * - "z" Zero-arg:
75
 *   - Is known to always consume exactly 0 stack elements.
76
 *   - For example after(n) = <n> OP_CHECKLOCKTIMEVERIFY
77
 * - "o" One-arg:
78
 *   - Is known to always consume exactly 1 stack element.
79
 *   - Conflicts with property 'z'
80
 *   - For example sha256(hash) = OP_SIZE 32 OP_EQUALVERIFY OP_SHA256 <hash> OP_EQUAL
81
 * - "n" Nonzero:
82
 *   - For every way this expression can be satisfied, a satisfaction exists that never needs
83
 *     a zero top stack element.
84
 *   - Conflicts with property 'z' and with type 'W'.
85
 * - "d" Dissatisfiable:
86
 *   - There is an easy way to construct a dissatisfaction for this expression.
87
 *   - Conflicts with type 'V'.
88
 * - "u" Unit:
89
 *   - In case of satisfaction, an exact 1 is put on the stack (rather than just nonzero).
90
 *   - Conflicts with type 'V'.
91
 *
92
 * Additional type properties help reasoning about nonmalleability:
93
 * - "e" Expression:
94
 *   - This implies property 'd', but the dissatisfaction is nonmalleable.
95
 *   - This generally requires 'e' for all subexpressions which are invoked for that
96
 *     dissatisfaction, and property 'f' for the unexecuted subexpressions in that case.
97
 *   - Conflicts with type 'V'.
98
 * - "f" Forced:
99
 *   - Dissatisfactions (if any) for this expression always involve at least one signature.
100
 *   - Is always true for type 'V'.
101
 * - "s" Safe:
102
 *   - Satisfactions for this expression always involve at least one signature.
103
 * - "m" Nonmalleable:
104
 *   - For every way this expression can be satisfied (which may be none),
105
 *     a nonmalleable satisfaction exists.
106
 *   - This generally requires 'm' for all subexpressions, and 'e' for all subexpressions
107
 *     which are dissatisfied when satisfying the parent.
108
 *
109
 * One type property is an implementation detail:
110
 * - "x" Expensive verify:
111
 *   - Expressions with this property have a script whose last opcode is not EQUAL, CHECKSIG, or CHECKMULTISIG.
112
 *   - Not having this property means that it can be converted to a V at no cost (by switching to the
113
 *     -VERIFY version of the last opcode).
114
 *
115
 * Five more type properties for representing timelock information. Spend paths
116
 * in miniscripts containing conflicting timelocks and heightlocks cannot be spent together.
117
 * This helps users detect if miniscript does not match the semantic behaviour the
118
 * user expects.
119
 * - "g" Whether the branch contains a relative time timelock
120
 * - "h" Whether the branch contains a relative height timelock
121
 * - "i" Whether the branch contains an absolute time timelock
122
 * - "j" Whether the branch contains an absolute height timelock
123
 * - "k"
124
 *   - Whether all satisfactions of this expression don't contain a mix of heightlock and timelock
125
 *     of the same type.
126
 *   - If the miniscript does not have the "k" property, the miniscript template will not match
127
 *     the user expectation of the corresponding spending policy.
128
 * For each of these properties the subset rule holds: an expression with properties X, Y, and Z, is also
129
 * valid in places where an X, a Y, a Z, an XY, ... is expected.
130
*/
131
class Type {
132
    //! Internal bitmap of properties (see ""_mst operator for details).
133
    uint32_t m_flags;
134
135
    //! Internal constructor used by the ""_mst operator.
136
36.3M
    explicit constexpr Type(uint32_t flags) : m_flags(flags) {}
137
138
public:
139
    //! The only way to publicly construct a Type is using this literal operator.
140
    friend consteval Type operator""_mst(const char* c, size_t l);
141
142
    //! Compute the type with the union of properties.
143
18.1M
    constexpr Type operator|(Type x) const { return Type(m_flags | x.m_flags); }
144
145
    //! Compute the type with the intersection of properties.
146
18.0M
    constexpr Type operator&(Type x) const { return Type(m_flags & x.m_flags); }
147
148
    //! Check whether the left hand's properties are superset of the right's (= left is a subtype of right).
149
330M
    constexpr bool operator<<(Type x) const { return (x.m_flags & ~m_flags) == 0; }
150
151
    //! Comparison operator to enable use in sets/maps (total ordering incompatible with <<).
152
0
    constexpr bool operator<(Type x) const { return m_flags < x.m_flags; }
153
154
    //! Equality operator.
155
7.97M
    constexpr bool operator==(Type x) const { return m_flags == x.m_flags; }
156
157
    //! The empty type if x is false, itself otherwise.
158
94.1k
    constexpr Type If(bool x) const { return Type(x ? m_flags : 0); }
159
};
160
161
//! Literal operator to construct Type objects.
162
inline consteval Type operator""_mst(const char* c, size_t l)
163
{
164
    Type typ{0};
165
166
    for (const char *p = c; p < c + l; p++) {
167
        typ = typ | Type(
168
            *p == 'B' ? 1 << 0 : // Base type
169
            *p == 'V' ? 1 << 1 : // Verify type
170
            *p == 'K' ? 1 << 2 : // Key type
171
            *p == 'W' ? 1 << 3 : // Wrapped type
172
            *p == 'z' ? 1 << 4 : // Zero-arg property
173
            *p == 'o' ? 1 << 5 : // One-arg property
174
            *p == 'n' ? 1 << 6 : // Nonzero arg property
175
            *p == 'd' ? 1 << 7 : // Dissatisfiable property
176
            *p == 'u' ? 1 << 8 : // Unit property
177
            *p == 'e' ? 1 << 9 : // Expression property
178
            *p == 'f' ? 1 << 10 : // Forced property
179
            *p == 's' ? 1 << 11 : // Safe property
180
            *p == 'm' ? 1 << 12 : // Nonmalleable property
181
            *p == 'x' ? 1 << 13 : // Expensive verify
182
            *p == 'g' ? 1 << 14 : // older: contains relative time timelock   (csv_time)
183
            *p == 'h' ? 1 << 15 : // older: contains relative height timelock (csv_height)
184
            *p == 'i' ? 1 << 16 : // after: contains time timelock   (cltv_time)
185
            *p == 'j' ? 1 << 17 : // after: contains height timelock   (cltv_height)
186
            *p == 'k' ? 1 << 18 : // does not contain a combination of height and time locks
187
            (throw std::logic_error("Unknown character in _mst literal"), 0)
188
        );
189
    }
190
191
    return typ;
192
}
193
194
using Opcode = std::pair<opcodetype, std::vector<unsigned char>>;
195
196
template<typename Key> class Node;
197
198
//! Unordered traversal of a miniscript node tree.
199
template <typename Key, std::invocable<const Node<Key>&> Fn>
200
void ForEachNode(const Node<Key>& root, Fn&& fn)
201
792
{
202
792
    std::vector<std::reference_wrapper<const Node<Key>>> stack{root};
203
996k
    while (!stack.empty()) {
204
995k
        const Node<Key>& node = stack.back();
205
995k
        std::invoke(fn, node);
206
995k
        stack.pop_back();
207
995k
        for (const auto& sub : node.Subs()) {
208
994k
            stack.emplace_back(sub);
209
994k
        }
210
995k
    }
211
792
}
212
213
//! The different node types in miniscript.
214
enum class Fragment {
215
    JUST_0,    //!< OP_0
216
    JUST_1,    //!< OP_1
217
    PK_K,      //!< [key]
218
    PK_H,      //!< OP_DUP OP_HASH160 [keyhash] OP_EQUALVERIFY
219
    OLDER,     //!< [n] OP_CHECKSEQUENCEVERIFY
220
    AFTER,     //!< [n] OP_CHECKLOCKTIMEVERIFY
221
    SHA256,    //!< OP_SIZE 32 OP_EQUALVERIFY OP_SHA256 [hash] OP_EQUAL
222
    HASH256,   //!< OP_SIZE 32 OP_EQUALVERIFY OP_HASH256 [hash] OP_EQUAL
223
    RIPEMD160, //!< OP_SIZE 32 OP_EQUALVERIFY OP_RIPEMD160 [hash] OP_EQUAL
224
    HASH160,   //!< OP_SIZE 32 OP_EQUALVERIFY OP_HASH160 [hash] OP_EQUAL
225
    WRAP_A,    //!< OP_TOALTSTACK [X] OP_FROMALTSTACK
226
    WRAP_S,    //!< OP_SWAP [X]
227
    WRAP_C,    //!< [X] OP_CHECKSIG
228
    WRAP_D,    //!< OP_DUP OP_IF [X] OP_ENDIF
229
    WRAP_V,    //!< [X] OP_VERIFY (or -VERIFY version of last opcode in X)
230
    WRAP_J,    //!< OP_SIZE OP_0NOTEQUAL OP_IF [X] OP_ENDIF
231
    WRAP_N,    //!< [X] OP_0NOTEQUAL
232
    AND_V,     //!< [X] [Y]
233
    AND_B,     //!< [X] [Y] OP_BOOLAND
234
    OR_B,      //!< [X] [Y] OP_BOOLOR
235
    OR_C,      //!< [X] OP_NOTIF [Y] OP_ENDIF
236
    OR_D,      //!< [X] OP_IFDUP OP_NOTIF [Y] OP_ENDIF
237
    OR_I,      //!< OP_IF [X] OP_ELSE [Y] OP_ENDIF
238
    ANDOR,     //!< [X] OP_NOTIF [Z] OP_ELSE [Y] OP_ENDIF
239
    THRESH,    //!< [X1] ([Xn] OP_ADD)* [k] OP_EQUAL
240
    MULTI,     //!< [k] [key_n]* [n] OP_CHECKMULTISIG (only available within P2WSH context)
241
    MULTI_A,   //!< [key_0] OP_CHECKSIG ([key_n] OP_CHECKSIGADD)* [k] OP_NUMEQUAL (only within Tapscript ctx)
242
    // AND_N(X,Y) is represented as ANDOR(X,Y,0)
243
    // WRAP_T(X) is represented as AND_V(X,1)
244
    // WRAP_L(X) is represented as OR_I(0,X)
245
    // WRAP_U(X) is represented as OR_I(X,0)
246
};
247
248
enum class Availability {
249
    NO,
250
    YES,
251
    MAYBE,
252
};
253
254
enum class MiniscriptContext {
255
    P2WSH,
256
    TAPSCRIPT,
257
};
258
259
/** Whether the context Tapscript, ensuring the only other possibility is P2WSH. */
260
constexpr bool IsTapscript(MiniscriptContext ms_ctx)
261
26.2M
{
262
26.2M
    switch (ms_ctx) {
263
66.2k
        case MiniscriptContext::P2WSH: return false;
264
26.1M
        case MiniscriptContext::TAPSCRIPT: return true;
265
26.2M
    }
266
26.2M
    assert(false);
267
0
}
268
269
namespace internal {
270
271
//! The maximum size of a witness item for a Miniscript under Tapscript context. (A BIP340 signature with a sighash type byte.)
272
static constexpr uint32_t MAX_TAPMINISCRIPT_STACK_ELEM_SIZE{65};
273
274
//! version + nLockTime
275
constexpr uint32_t TX_OVERHEAD{4 + 4};
276
//! prevout + nSequence + scriptSig
277
constexpr uint32_t TXIN_BYTES_NO_WITNESS{36 + 4 + 1};
278
//! nValue + script len + OP_0 + pushdata 32.
279
constexpr uint32_t P2WSH_TXOUT_BYTES{8 + 1 + 1 + 33};
280
//! Data other than the witness in a transaction. Overhead + vin count + one vin + vout count + one vout + segwit marker
281
constexpr uint32_t TX_BODY_LEEWAY_WEIGHT{(TX_OVERHEAD + GetSizeOfCompactSize(1) + TXIN_BYTES_NO_WITNESS + GetSizeOfCompactSize(1) + P2WSH_TXOUT_BYTES) * WITNESS_SCALE_FACTOR + 2};
282
//! Maximum possible stack size to spend a Taproot output (excluding the script itself).
283
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};
284
/** The maximum size of a script depending on the context. */
285
constexpr uint32_t MaxScriptSize(MiniscriptContext ms_ctx)
286
7.97M
{
287
7.97M
    if (IsTapscript(ms_ctx)) {
288
        // Leaf scripts under Tapscript are not explicitly limited in size. They are only implicitly
289
        // bounded by the maximum standard size of a spending transaction. Let the maximum script
290
        // size conservatively be small enough such that even a maximum sized witness and a reasonably
291
        // sized spending transaction can spend an output paying to this script without running into
292
        // the maximum standard tx size limit.
293
7.94M
        constexpr auto max_size{MAX_STANDARD_TX_WEIGHT - TX_BODY_LEEWAY_WEIGHT - MAX_TAPSCRIPT_SAT_SIZE};
294
7.94M
        return max_size - GetSizeOfCompactSize(max_size);
295
7.94M
    }
296
23.8k
    return MAX_STANDARD_P2WSH_SCRIPT_SIZE;
297
7.97M
}
298
299
//! Helper function for Node::CalcType.
300
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);
301
302
//! Helper function for Node::CalcScriptLen.
303
size_t ComputeScriptLen(Fragment fragment, Type sub0typ, size_t subsize, uint32_t k, size_t n_subs, size_t n_keys, MiniscriptContext ms_ctx);
304
305
//! A helper sanitizer/checker for the output of CalcType.
306
Type SanitizeType(Type x);
307
308
//! An object representing a sequence of witness stack elements.
309
struct InputStack {
310
    /** Whether this stack is valid for its intended purpose (satisfaction or dissatisfaction of a Node).
311
     *  The MAYBE value is used for size estimation, when keys/preimages may actually be unavailable,
312
     *  but may be available at signing time. This makes the InputStack structure and signing logic,
313
     *  filled with dummy signatures/preimages usable for witness size estimation.
314
     */
315
    Availability available = Availability::YES;
316
    //! Whether this stack contains a digital signature.
317
    bool has_sig = false;
318
    //! Whether this stack is malleable (can be turned into an equally valid other stack by a third party).
319
    bool malleable = false;
320
    //! Whether this stack is non-canonical (using a construction known to be unnecessary for satisfaction).
321
    //! Note that this flag does not affect the satisfaction algorithm; it is only used for sanity checking.
322
    bool non_canon = false;
323
    //! Serialized witness size.
324
    size_t size = 0;
325
    //! Data elements.
326
    std::vector<std::vector<unsigned char>> stack;
327
    //! Construct an empty stack (valid).
328
4.49k
    InputStack() = default;
329
    //! Construct a valid single-element stack (with an element up to 75 bytes).
330
489k
    InputStack(std::vector<unsigned char> in) : size(in.size() + 1), stack(Vector(std::move(in))) {}
331
    //! Change availability
332
    InputStack& SetAvailable(Availability avail);
333
    //! Mark this input stack as having a signature.
334
    InputStack& SetWithSig();
335
    //! Mark this input stack as non-canonical (known to not be necessary in non-malleable satisfactions).
336
    InputStack& SetNonCanon();
337
    //! Mark this input stack as malleable.
338
    InputStack& SetMalleable(bool x = true);
339
    //! Concatenate two input stacks.
340
    friend InputStack operator+(InputStack a, InputStack b);
341
    //! Choose between two potential input stacks.
342
    friend InputStack operator|(InputStack a, InputStack b);
343
};
344
345
/** A stack consisting of a single zero-length element (interpreted as 0 by the script interpreter in numeric context). */
346
static const auto ZERO = InputStack(std::vector<unsigned char>());
347
/** A stack consisting of a single malleable 32-byte 0x0000...0000 element (for dissatisfying hash challenges). */
348
static const auto ZERO32 = InputStack(std::vector<unsigned char>(32, 0)).SetMalleable();
349
/** A stack consisting of a single 0x01 element (interpreted as 1 by the script interpreted in numeric context). */
350
static const auto ONE = InputStack(Vector((unsigned char)1));
351
/** The empty stack. */
352
static const auto EMPTY = InputStack();
353
/** A stack representing the lack of any (dis)satisfactions. */
354
static const auto INVALID = InputStack().SetAvailable(Availability::NO);
355
356
//! A pair of a satisfaction and a dissatisfaction InputStack.
357
struct InputResult {
358
    InputStack nsat, sat;
359
360
    template<typename A, typename B>
361
839k
    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
361
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
361
993
    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
361
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
361
41.7k
    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
361
2.22k
    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
361
2.58k
    InputResult(A&& in_nsat, B&& in_sat) : nsat(std::forward<A>(in_nsat)), sat(std::forward<B>(in_sat)) {}
362
};
363
364
//! Class whose objects represent the maximum of a list of integers.
365
template <typename I>
366
class MaxInt
367
{
368
    bool valid;
369
    I value;
370
371
public:
372
42.3k
    MaxInt() : valid(false), value(0) {}
373
105k
    MaxInt(I val) : valid(true), value(val) {}
374
375
2.68k
    bool Valid() const { return valid; }
376
2.67k
    I Value() const { return value; }
377
378
57.2k
    friend MaxInt<I> operator+(const MaxInt<I>& a, const MaxInt<I>& b) {
379
57.2k
        if (!a.valid || !b.valid) return {};
380
42.5k
        return a.value + b.value;
381
57.2k
    }
382
383
9.79k
    friend MaxInt<I> operator|(const MaxInt<I>& a, const MaxInt<I>& b) {
384
9.79k
        if (!a.valid) return b;
385
8.55k
        if (!b.valid) return a;
386
7.24k
        return std::max(a.value, b.value);
387
8.55k
    }
388
};
389
390
struct Ops {
391
    //! Non-push opcodes.
392
    uint32_t count;
393
    //! Number of keys in possibly executed OP_CHECKMULTISIG(VERIFY)s to satisfy.
394
    MaxInt<uint32_t> sat;
395
    //! Number of keys in possibly executed OP_CHECKMULTISIG(VERIFY)s to dissatisfy.
396
    MaxInt<uint32_t> dsat;
397
398
9.01M
    Ops(uint32_t in_count, MaxInt<uint32_t> in_sat, MaxInt<uint32_t> in_dsat) : count(in_count), sat(in_sat), dsat(in_dsat) {};
399
};
400
401
/** A data structure to help the calculation of stack size limits.
402
 *
403
 * Conceptually, every SatInfo object corresponds to a (possibly empty) set of script execution
404
 * traces (sequences of opcodes).
405
 * - SatInfo{} corresponds to the empty set.
406
 * - SatInfo{n, e} corresponds to a single trace whose net effect is removing n elements from the
407
 *   stack (may be negative for a net increase), and reaches a maximum of e stack elements more
408
 *   than it ends with.
409
 * - operator| is the union operation: (a | b) corresponds to the union of the traces in a and the
410
 *   traces in b.
411
 * - operator+ is the concatenation operator: (a + b) corresponds to the set of traces formed by
412
 *   concatenating any trace in a with any trace in b.
413
 *
414
 * Its fields are:
415
 * - valid is true if the set is non-empty.
416
 * - netdiff (if valid) is the largest difference between stack size at the beginning and at the
417
 *   end of the script across all traces in the set.
418
 * - exec (if valid) is the largest difference between stack size anywhere during execution and at
419
 *   the end of the script, across all traces in the set (note that this is not necessarily due
420
 *   to the same trace as the one that resulted in the value for netdiff).
421
 *
422
 * This allows us to build up stack size limits for any script efficiently, by starting from the
423
 * individual opcodes miniscripts correspond to, using concatenation to construct scripts, and
424
 * using the union operation to choose between execution branches. Since any top-level script
425
 * satisfaction ends with a single stack element, we know that for a full script:
426
 * - netdiff+1 is the maximal initial stack size (relevant for P2WSH stack limits).
427
 * - exec+1 is the maximal stack size reached during execution (relevant for P2TR stack limits).
428
 *
429
 * Mathematically, SatInfo forms a semiring:
430
 * - operator| is the semiring addition operator, with identity SatInfo{}, and which is commutative
431
 *   and associative.
432
 * - operator+ is the semiring multiplication operator, with identity SatInfo{0}, and which is
433
 *   associative.
434
 * - operator+ is distributive over operator|, so (a + (b | c)) = (a+b | a+c). This means we do not
435
 *   need to actually materialize all possible full execution traces over the whole script (which
436
 *   may be exponential in the length of the script); instead we can use the union operation at the
437
 *   individual subexpression level, and concatenate the result with subexpressions before and
438
 *   after it.
439
 * - It is not a commutative semiring, because a+b can differ from b+a. For example, "OP_1 OP_DROP"
440
 *   has exec=1, while "OP_DROP OP_1" has exec=0.
441
 */
442
class SatInfo
443
{
444
    //! Whether a canonical satisfaction/dissatisfaction is possible at all.
445
    bool valid;
446
    //! How much higher the stack size at start of execution can be compared to at the end.
447
    int32_t netdiff;
448
    //! How much higher the stack size can be during execution compared to at the end.
449
    int32_t exec;
450
451
public:
452
    /** Empty script set. */
453
26.6k
    constexpr SatInfo() noexcept : valid(false), netdiff(0), exec(0) {}
454
455
    /** Script set with a single script in it, with specified netdiff and exec. */
456
    constexpr SatInfo(int32_t in_netdiff, int32_t in_exec) noexcept :
457
138k
        valid{true}, netdiff{in_netdiff}, exec{in_exec} {}
458
459
7.17k
    bool Valid() const { return valid; }
460
2.71k
    int32_t NetDiff() const { return netdiff; }
461
4.43k
    int32_t Exec() const { return exec; }
462
463
    /** Script set union. */
464
    constexpr friend SatInfo operator|(const SatInfo& a, const SatInfo& b) noexcept
465
4.89k
    {
466
        // Union with an empty set is itself.
467
4.89k
        if (!a.valid) return b;
468
4.28k
        if (!b.valid) return a;
469
        // Otherwise the netdiff and exec of the union is the maximum of the individual values.
470
3.62k
        return {std::max(a.netdiff, b.netdiff), std::max(a.exec, b.exec)};
471
4.28k
    }
472
473
    /** Script set concatenation. */
474
    constexpr friend SatInfo operator+(const SatInfo& a, const SatInfo& b) noexcept
475
80.2k
    {
476
        // Concatenation with an empty set yields an empty set.
477
80.2k
        if (!a.valid || !b.valid) return {};
478
        // Otherwise, the maximum stack size difference for the combined scripts is the sum of the
479
        // netdiffs, and the maximum stack size difference anywhere is either b.exec (if the
480
        // maximum occurred in b) or b.netdiff+a.exec (if the maximum occurred in a).
481
67.4k
        return {a.netdiff + b.netdiff, std::max(b.exec, b.netdiff + a.exec)};
482
80.2k
    }
483
484
    /** The empty script. */
485
820
    static constexpr SatInfo Empty() noexcept { return {0, 0}; }
486
    /** A script consisting of a single push opcode. */
487
18.0k
    static constexpr SatInfo Push() noexcept { return {-1, 0}; }
488
    /** A script consisting of a single hash opcode. */
489
1.21k
    static constexpr SatInfo Hash() noexcept { return {0, 0}; }
490
    /** A script consisting of just a repurposed nop (OP_CHECKLOCKTIMEVERIFY, OP_CHECKSEQUENCEVERIFY). */
491
9.14k
    static constexpr SatInfo Nop() noexcept { return {0, 0}; }
492
    /** A script consisting of just OP_IF or OP_NOTIF. Note that OP_ELSE and OP_ENDIF have no stack effect. */
493
2.84k
    static constexpr SatInfo If() noexcept { return {1, 1}; }
494
    /** A script consisting of just a binary operator (OP_BOOLAND, OP_BOOLOR, OP_ADD). */
495
15.7k
    static constexpr SatInfo BinaryOp() noexcept { return {1, 1}; }
496
497
    // Scripts for specific individual opcodes.
498
1.05k
    static constexpr SatInfo OP_DUP() noexcept { return {-1, 0}; }
499
378
    static constexpr SatInfo OP_IFDUP(bool nonzero) noexcept { return {nonzero ? -1 : 0, 0}; }
500
1.21k
    static constexpr SatInfo OP_EQUALVERIFY() noexcept { return {2, 2}; }
501
1.22k
    static constexpr SatInfo OP_EQUAL() noexcept { return {1, 1}; }
502
432
    static constexpr SatInfo OP_SIZE() noexcept { return {-1, 0}; }
503
12.5k
    static constexpr SatInfo OP_CHECKSIG() noexcept { return {1, 1}; }
504
32
    static constexpr SatInfo OP_0NOTEQUAL() noexcept { return {0, 0}; }
505
1.71k
    static constexpr SatInfo OP_VERIFY() noexcept { return {1, 1}; }
506
};
507
508
class StackSize
509
{
510
    SatInfo sat, dsat;
511
512
public:
513
28.9k
    constexpr StackSize(SatInfo in_sat, SatInfo in_dsat) noexcept : sat(in_sat), dsat(in_dsat) {};
514
7.30k
    constexpr StackSize(SatInfo in_both) noexcept : sat(in_both), dsat(in_both) {};
515
516
47.2k
    const SatInfo& Sat() const { return sat; }
517
28.1k
    const SatInfo& Dsat() const { return dsat; }
518
};
519
520
struct WitnessSize {
521
    //! Maximum witness size to satisfy;
522
    MaxInt<uint32_t> sat;
523
    //! Maximum witness size to dissatisfy;
524
    MaxInt<uint32_t> dsat;
525
526
30.0k
    WitnessSize(MaxInt<uint32_t> in_sat, MaxInt<uint32_t> in_dsat) : sat(in_sat), dsat(in_dsat) {};
527
};
528
529
struct NoDupCheck {};
530
531
} // namespace internal
532
533
//! A node in a miniscript expression.
534
template <typename Key>
535
class Node
536
{
537
    //! What node type this node is.
538
    enum Fragment fragment;
539
    //! The k parameter (time for OLDER/AFTER, threshold for THRESH(_M))
540
    uint32_t k = 0;
541
    //! The keys used by this expression (only for PK_K/PK_H/MULTI)
542
    std::vector<Key> keys;
543
    //! The data bytes in this expression (only for HASH160/HASH256/SHA256/RIPEMD160).
544
    std::vector<unsigned char> data;
545
    //! Subexpressions (for WRAP_*/AND_*/OR_*/ANDOR/THRESH)
546
    std::vector<Node> subs;
547
    //! The Script context for this node. Either P2WSH or Tapscript.
548
    MiniscriptContext m_script_ctx;
549
550
public:
551
    // Permit 1 level deep recursion since we own instances of our own type.
552
    // NOLINTBEGIN(misc-no-recursion)
553
    ~Node()
554
19.1M
    {
555
        // Destroy the subexpressions iteratively after moving out their
556
        // subexpressions to avoid a stack-overflow due to recursive calls to
557
        // the subs' destructors.
558
        // We move vectors in order to only update array-pointers inside them
559
        // rather than moving individual Node instances which would involve
560
        // moving/copying each Node field.
561
19.1M
        std::vector<std::vector<Node>> queue;
562
19.1M
        queue.push_back(std::move(subs));
563
28.1M
        do {
564
28.1M
            auto flattening{std::move(queue.back())};
565
28.1M
            queue.pop_back();
566
28.1M
            for (Node& n : flattening) {
567
9.00M
                if (!n.subs.empty()) queue.push_back(std::move(n.subs));
568
9.00M
            }
569
28.1M
        } while (!queue.empty());
570
19.1M
    }
miniscript::Node<CPubKey>::~Node()
Line
Count
Source
554
73.7k
    {
555
        // Destroy the subexpressions iteratively after moving out their
556
        // subexpressions to avoid a stack-overflow due to recursive calls to
557
        // the subs' destructors.
558
        // We move vectors in order to only update array-pointers inside them
559
        // rather than moving individual Node instances which would involve
560
        // moving/copying each Node field.
561
73.7k
        std::vector<std::vector<Node>> queue;
562
73.7k
        queue.push_back(std::move(subs));
563
90.7k
        do {
564
90.7k
            auto flattening{std::move(queue.back())};
565
90.7k
            queue.pop_back();
566
90.7k
            for (Node& n : flattening) {
567
26.2k
                if (!n.subs.empty()) queue.push_back(std::move(n.subs));
568
26.2k
            }
569
90.7k
        } while (!queue.empty());
570
73.7k
    }
miniscript::Node<unsigned int>::~Node()
Line
Count
Source
554
4.52M
    {
555
        // Destroy the subexpressions iteratively after moving out their
556
        // subexpressions to avoid a stack-overflow due to recursive calls to
557
        // the subs' destructors.
558
        // We move vectors in order to only update array-pointers inside them
559
        // rather than moving individual Node instances which would involve
560
        // moving/copying each Node field.
561
4.52M
        std::vector<std::vector<Node>> queue;
562
4.52M
        queue.push_back(std::move(subs));
563
6.24M
        do {
564
6.24M
            auto flattening{std::move(queue.back())};
565
6.24M
            queue.pop_back();
566
6.24M
            for (Node& n : flattening) {
567
1.72M
                if (!n.subs.empty()) queue.push_back(std::move(n.subs));
568
1.72M
            }
569
6.24M
        } while (!queue.empty());
570
4.52M
    }
miniscript::Node<XOnlyPubKey>::~Node()
Line
Count
Source
554
14.5M
    {
555
        // Destroy the subexpressions iteratively after moving out their
556
        // subexpressions to avoid a stack-overflow due to recursive calls to
557
        // the subs' destructors.
558
        // We move vectors in order to only update array-pointers inside them
559
        // rather than moving individual Node instances which would involve
560
        // moving/copying each Node field.
561
14.5M
        std::vector<std::vector<Node>> queue;
562
14.5M
        queue.push_back(std::move(subs));
563
21.7M
        do {
564
21.7M
            auto flattening{std::move(queue.back())};
565
21.7M
            queue.pop_back();
566
21.7M
            for (Node& n : flattening) {
567
7.25M
                if (!n.subs.empty()) queue.push_back(std::move(n.subs));
568
7.25M
            }
569
21.7M
        } while (!queue.empty());
570
14.5M
    }
571
    // NOLINTEND(misc-no-recursion)
572
573
    Node<Key> Clone() const
574
190
    {
575
        // Use TreeEval() to avoid a stack-overflow due to recursion
576
531k
        auto upfn = [](const Node& node, std::span<Node> children) {
577
531k
            std::vector<Node> new_subs;
578
531k
            for (auto& child : children) {
579
                // It's fine to move from children as they are new nodes having
580
                // been produced by calling this function one level down.
581
530k
                new_subs.push_back(std::move(child));
582
530k
            }
583
531k
            return Node{internal::NoDupCheck{}, node.m_script_ctx, node.fragment, std::move(new_subs), node.keys, node.data, node.k};
584
531k
        };
585
190
        return TreeEval<Node>(upfn);
586
190
    }
587
588
1.00M
    enum Fragment Fragment() const { return fragment; }
miniscript::Node<CPubKey>::Fragment() const
Line
Count
Source
588
8.47k
    enum Fragment Fragment() const { return fragment; }
miniscript::Node<unsigned int>::Fragment() const
Line
Count
Source
588
995k
    enum Fragment Fragment() const { return fragment; }
589
2.35k
    uint32_t K() const { return k; }
miniscript::Node<CPubKey>::K() const
Line
Count
Source
589
2.10k
    uint32_t K() const { return k; }
miniscript::Node<unsigned int>::K() const
Line
Count
Source
589
249
    uint32_t K() const { return k; }
590
8.47k
    const std::vector<Key>& Keys() const { return keys; }
591
48
    const std::vector<unsigned char>& Data() const { return data; }
592
2.20M
    const std::vector<Node>& Subs() const { return subs; }
miniscript::Node<CPubKey>::Subs() const
Line
Count
Source
592
8.47k
    const std::vector<Node>& Subs() const { return subs; }
miniscript::Node<unsigned int>::Subs() const
Line
Count
Source
592
2.19M
    const std::vector<Node>& Subs() const { return subs; }
593
594
private:
595
    //! Cached ops counts.
596
    internal::Ops ops;
597
    //! Cached stack size bounds.
598
    internal::StackSize ss;
599
    //! Cached witness size bounds.
600
    internal::WitnessSize ws;
601
    //! Cached expression type (computed by CalcType and fed through SanitizeType).
602
    Type typ;
603
    //! Cached script length (computed by CalcScriptLen).
604
    size_t scriptlen;
605
    //! Whether a public key appears more than once in this node. This value is initialized
606
    //! by all constructors except the NoDupCheck ones. The NoDupCheck ones skip the
607
    //! computation, requiring it to be done manually by invoking DuplicateKeyCheck().
608
    //! DuplicateKeyCheck(), or a non-NoDupCheck constructor, will compute has_duplicate_keys
609
    //! for all subnodes as well.
610
    mutable std::optional<bool> has_duplicate_keys;
611
612
    // Constructor which takes all of the data that a Node could possibly contain.
613
    // This is kept private as no valid fragment has all of these arguments.
614
    // Only used by Clone()
615
    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)
616
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()) {}
617
618
    //! Compute the length of the script for this miniscript (including children).
619
    size_t CalcScriptLen() const
620
9.01M
    {
621
9.01M
        size_t subsize = 0;
622
9.01M
        for (const auto& sub : subs) {
623
9.00M
            subsize += sub.ScriptSize();
624
9.00M
        }
625
9.01M
        Type sub0type = subs.size() > 0 ? subs[0].GetType() : ""_mst;
626
9.01M
        return internal::ComputeScriptLen(fragment, sub0type, subsize, k, subs.size(), keys.size(), m_script_ctx);
627
9.01M
    }
miniscript::Node<CPubKey>::CalcScriptLen() const
Line
Count
Source
620
28.5k
    {
621
28.5k
        size_t subsize = 0;
622
28.5k
        for (const auto& sub : subs) {
623
26.2k
            subsize += sub.ScriptSize();
624
26.2k
        }
625
28.5k
        Type sub0type = subs.size() > 0 ? subs[0].GetType() : ""_mst;
626
28.5k
        return internal::ComputeScriptLen(fragment, sub0type, subsize, k, subs.size(), keys.size(), m_script_ctx);
627
28.5k
    }
miniscript::Node<unsigned int>::CalcScriptLen() const
Line
Count
Source
620
1.72M
    {
621
1.72M
        size_t subsize = 0;
622
1.72M
        for (const auto& sub : subs) {
623
1.72M
            subsize += sub.ScriptSize();
624
1.72M
        }
625
1.72M
        Type sub0type = subs.size() > 0 ? subs[0].GetType() : ""_mst;
626
1.72M
        return internal::ComputeScriptLen(fragment, sub0type, subsize, k, subs.size(), keys.size(), m_script_ctx);
627
1.72M
    }
miniscript::Node<XOnlyPubKey>::CalcScriptLen() const
Line
Count
Source
620
7.25M
    {
621
7.25M
        size_t subsize = 0;
622
7.25M
        for (const auto& sub : subs) {
623
7.25M
            subsize += sub.ScriptSize();
624
7.25M
        }
625
7.25M
        Type sub0type = subs.size() > 0 ? subs[0].GetType() : ""_mst;
626
7.25M
        return internal::ComputeScriptLen(fragment, sub0type, subsize, k, subs.size(), keys.size(), m_script_ctx);
627
7.25M
    }
628
629
    /* Apply a recursive algorithm to a Miniscript tree, without actual recursive calls.
630
     *
631
     * The algorithm is defined by two functions: downfn and upfn. Conceptually, the
632
     * result can be thought of as first using downfn to compute a "state" for each node,
633
     * from the root down to the leaves. Then upfn is used to compute a "result" for each
634
     * node, from the leaves back up to the root, which is then returned. In the actual
635
     * implementation, both functions are invoked in an interleaved fashion, performing a
636
     * depth-first traversal of the tree.
637
     *
638
     * In more detail, it is invoked as node.TreeEvalMaybe<Result>(root, downfn, upfn):
639
     * - root is the state of the root node, of type State.
640
     * - downfn is a callable (State&, const Node&, size_t) -> State, which given a
641
     *   node, its state, and an index of one of its children, computes the state of that
642
     *   child. It can modify the state. Children of a given node will have downfn()
643
     *   called in order.
644
     * - upfn is a callable (State&&, const Node&, std::span<Result>) -> std::optional<Result>,
645
     *   which given a node, its state, and a span of the results of its children,
646
     *   computes the result of the node. If std::nullopt is returned by upfn,
647
     *   TreeEvalMaybe() immediately returns std::nullopt.
648
     * The return value of TreeEvalMaybe is the result of the root node.
649
     *
650
     * Result type cannot be bool due to the std::vector<bool> specialization.
651
     */
652
    template<typename Result, typename State, typename DownFn, typename UpFn>
653
    std::optional<Result> TreeEvalMaybe(State root_state, DownFn downfn, UpFn upfn) const
654
16.2k
    {
655
        /** Entries of the explicit stack tracked in this algorithm. */
656
16.2k
        struct StackElem
657
16.2k
        {
658
16.2k
            const Node& node; //!< The node being evaluated.
659
16.2k
            size_t expanded; //!< How many children of this node have been expanded.
660
16.2k
            State state; //!< The state for that node.
661
662
16.2k
            StackElem(const Node& node_, size_t exp_, State&& state_) :
663
22.3M
                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
663
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
663
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
663
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
663
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
663
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
663
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
663
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
663
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
663
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
663
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
663
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
663
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
663
7.25M
                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
663
7.25M
                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
663
3.23k
                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
663
3.23k
                node(node_), expanded(exp_), state(std::move(state_)) {}
664
16.2k
        };
665
        /* Stack of tree nodes being explored. */
666
16.2k
        std::vector<StackElem> stack;
667
        /* Results of subtrees so far. Their order and mapping to tree nodes
668
         * is implicitly defined by stack. */
669
16.2k
        std::vector<Result> results;
670
16.2k
        stack.emplace_back(*this, 0, std::move(root_state));
671
672
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
673
         * State variables are omitted for simplicity.
674
         *
675
         * First: stack=[(A,0)] results=[]
676
         *        stack=[(A,1),(B,0)] results=[]
677
         *        stack=[(A,1)] results=[B]
678
         *        stack=[(A,2),(C,0)] results=[B]
679
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
680
         *        stack=[(A,2),(C,1)] results=[B,D]
681
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
682
         *        stack=[(A,2),(C,2)] results=[B,D,E]
683
         *        stack=[(A,2)] results=[B,C]
684
         *        stack=[(A,3),(F,0)] results=[B,C]
685
         *        stack=[(A,3)] results=[B,C,F]
686
         * Final: stack=[] results=[A]
687
         */
688
44.7M
        while (stack.size()) {
689
44.7M
            const Node& node = stack.back().node;
690
44.7M
            if (stack.back().expanded < node.subs.size()) {
691
                /* We encounter a tree node with at least one unexpanded child.
692
                 * Expand it. By the time we hit this node again, the result of
693
                 * that child (and all earlier children) will be at the end of `results`. */
694
22.3M
                size_t child_index = stack.back().expanded++;
695
22.3M
                State child_state = downfn(stack.back().state, node, child_index);
696
22.3M
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
697
22.3M
                continue;
698
22.3M
            }
699
            // Invoke upfn with the last node.subs.size() elements of results as input.
700
44.7M
            assert(results.size() >= node.subs.size());
701
22.3M
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
702
22.3M
                std::span<Result>{results}.last(node.subs.size()))};
703
            // If evaluation returns std::nullopt, abort immediately.
704
22.3M
            if (!result) return {};
705
            // Replace the last node.subs.size() elements of results with the new result.
706
22.3M
            results.erase(results.end() - node.subs.size(), results.end());
707
22.3M
            results.push_back(std::move(*result));
708
22.3M
            stack.pop_back();
709
22.3M
        }
710
        // The final remaining results element is the root result, return it.
711
16.2k
        assert(results.size() >= 1);
712
16.2k
        CHECK_NONFATAL(results.size() == 1);
713
16.2k
        return std::move(results[0]);
714
16.2k
    }
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
654
375
    {
655
        /** Entries of the explicit stack tracked in this algorithm. */
656
375
        struct StackElem
657
375
        {
658
375
            const Node& node; //!< The node being evaluated.
659
375
            size_t expanded; //!< How many children of this node have been expanded.
660
375
            State state; //!< The state for that node.
661
662
375
            StackElem(const Node& node_, size_t exp_, State&& state_) :
663
375
                node(node_), expanded(exp_), state(std::move(state_)) {}
664
375
        };
665
        /* Stack of tree nodes being explored. */
666
375
        std::vector<StackElem> stack;
667
        /* Results of subtrees so far. Their order and mapping to tree nodes
668
         * is implicitly defined by stack. */
669
375
        std::vector<Result> results;
670
375
        stack.emplace_back(*this, 0, std::move(root_state));
671
672
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
673
         * State variables are omitted for simplicity.
674
         *
675
         * First: stack=[(A,0)] results=[]
676
         *        stack=[(A,1),(B,0)] results=[]
677
         *        stack=[(A,1)] results=[B]
678
         *        stack=[(A,2),(C,0)] results=[B]
679
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
680
         *        stack=[(A,2),(C,1)] results=[B,D]
681
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
682
         *        stack=[(A,2),(C,2)] results=[B,D,E]
683
         *        stack=[(A,2)] results=[B,C]
684
         *        stack=[(A,3),(F,0)] results=[B,C]
685
         *        stack=[(A,3)] results=[B,C,F]
686
         * Final: stack=[] results=[A]
687
         */
688
50.8k
        while (stack.size()) {
689
50.4k
            const Node& node = stack.back().node;
690
50.4k
            if (stack.back().expanded < node.subs.size()) {
691
                /* We encounter a tree node with at least one unexpanded child.
692
                 * Expand it. By the time we hit this node again, the result of
693
                 * that child (and all earlier children) will be at the end of `results`. */
694
25.0k
                size_t child_index = stack.back().expanded++;
695
25.0k
                State child_state = downfn(stack.back().state, node, child_index);
696
25.0k
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
697
25.0k
                continue;
698
25.0k
            }
699
            // Invoke upfn with the last node.subs.size() elements of results as input.
700
50.4k
            assert(results.size() >= node.subs.size());
701
25.4k
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
702
25.4k
                std::span<Result>{results}.last(node.subs.size()))};
703
            // If evaluation returns std::nullopt, abort immediately.
704
25.4k
            if (!result) return {};
705
            // Replace the last node.subs.size() elements of results with the new result.
706
25.4k
            results.erase(results.end() - node.subs.size(), results.end());
707
25.4k
            results.push_back(std::move(*result));
708
25.4k
            stack.pop_back();
709
25.4k
        }
710
        // The final remaining results element is the root result, return it.
711
375
        assert(results.size() >= 1);
712
375
        CHECK_NONFATAL(results.size() == 1);
713
375
        return std::move(results[0]);
714
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
654
4.82k
    {
655
        /** Entries of the explicit stack tracked in this algorithm. */
656
4.82k
        struct StackElem
657
4.82k
        {
658
4.82k
            const Node& node; //!< The node being evaluated.
659
4.82k
            size_t expanded; //!< How many children of this node have been expanded.
660
4.82k
            State state; //!< The state for that node.
661
662
4.82k
            StackElem(const Node& node_, size_t exp_, State&& state_) :
663
4.82k
                node(node_), expanded(exp_), state(std::move(state_)) {}
664
4.82k
        };
665
        /* Stack of tree nodes being explored. */
666
4.82k
        std::vector<StackElem> stack;
667
        /* Results of subtrees so far. Their order and mapping to tree nodes
668
         * is implicitly defined by stack. */
669
4.82k
        std::vector<Result> results;
670
4.82k
        stack.emplace_back(*this, 0, std::move(root_state));
671
672
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
673
         * State variables are omitted for simplicity.
674
         *
675
         * First: stack=[(A,0)] results=[]
676
         *        stack=[(A,1),(B,0)] results=[]
677
         *        stack=[(A,1)] results=[B]
678
         *        stack=[(A,2),(C,0)] results=[B]
679
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
680
         *        stack=[(A,2),(C,1)] results=[B,D]
681
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
682
         *        stack=[(A,2),(C,2)] results=[B,D,E]
683
         *        stack=[(A,2)] results=[B,C]
684
         *        stack=[(A,3),(F,0)] results=[B,C]
685
         *        stack=[(A,3)] results=[B,C,F]
686
         * Final: stack=[] results=[A]
687
         */
688
3.23M
        while (stack.size()) {
689
3.22M
            const Node& node = stack.back().node;
690
3.22M
            if (stack.back().expanded < node.subs.size()) {
691
                /* We encounter a tree node with at least one unexpanded child.
692
                 * Expand it. By the time we hit this node again, the result of
693
                 * that child (and all earlier children) will be at the end of `results`. */
694
1.61M
                size_t child_index = stack.back().expanded++;
695
1.61M
                State child_state = downfn(stack.back().state, node, child_index);
696
1.61M
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
697
1.61M
                continue;
698
1.61M
            }
699
            // Invoke upfn with the last node.subs.size() elements of results as input.
700
3.22M
            assert(results.size() >= node.subs.size());
701
1.61M
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
702
1.61M
                std::span<Result>{results}.last(node.subs.size()))};
703
            // If evaluation returns std::nullopt, abort immediately.
704
1.61M
            if (!result) return {};
705
            // Replace the last node.subs.size() elements of results with the new result.
706
1.61M
            results.erase(results.end() - node.subs.size(), results.end());
707
1.61M
            results.push_back(std::move(*result));
708
1.61M
            stack.pop_back();
709
1.61M
        }
710
        // The final remaining results element is the root result, return it.
711
4.82k
        assert(results.size() >= 1);
712
4.82k
        CHECK_NONFATAL(results.size() == 1);
713
4.82k
        return std::move(results[0]);
714
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
654
375
    {
655
        /** Entries of the explicit stack tracked in this algorithm. */
656
375
        struct StackElem
657
375
        {
658
375
            const Node& node; //!< The node being evaluated.
659
375
            size_t expanded; //!< How many children of this node have been expanded.
660
375
            State state; //!< The state for that node.
661
662
375
            StackElem(const Node& node_, size_t exp_, State&& state_) :
663
375
                node(node_), expanded(exp_), state(std::move(state_)) {}
664
375
        };
665
        /* Stack of tree nodes being explored. */
666
375
        std::vector<StackElem> stack;
667
        /* Results of subtrees so far. Their order and mapping to tree nodes
668
         * is implicitly defined by stack. */
669
375
        std::vector<Result> results;
670
375
        stack.emplace_back(*this, 0, std::move(root_state));
671
672
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
673
         * State variables are omitted for simplicity.
674
         *
675
         * First: stack=[(A,0)] results=[]
676
         *        stack=[(A,1),(B,0)] results=[]
677
         *        stack=[(A,1)] results=[B]
678
         *        stack=[(A,2),(C,0)] results=[B]
679
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
680
         *        stack=[(A,2),(C,1)] results=[B,D]
681
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
682
         *        stack=[(A,2),(C,2)] results=[B,D,E]
683
         *        stack=[(A,2)] results=[B,C]
684
         *        stack=[(A,3),(F,0)] results=[B,C]
685
         *        stack=[(A,3)] results=[B,C,F]
686
         * Final: stack=[] results=[A]
687
         */
688
50.8k
        while (stack.size()) {
689
50.4k
            const Node& node = stack.back().node;
690
50.4k
            if (stack.back().expanded < node.subs.size()) {
691
                /* We encounter a tree node with at least one unexpanded child.
692
                 * Expand it. By the time we hit this node again, the result of
693
                 * that child (and all earlier children) will be at the end of `results`. */
694
25.0k
                size_t child_index = stack.back().expanded++;
695
25.0k
                State child_state = downfn(stack.back().state, node, child_index);
696
25.0k
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
697
25.0k
                continue;
698
25.0k
            }
699
            // Invoke upfn with the last node.subs.size() elements of results as input.
700
50.4k
            assert(results.size() >= node.subs.size());
701
25.4k
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
702
25.4k
                std::span<Result>{results}.last(node.subs.size()))};
703
            // If evaluation returns std::nullopt, abort immediately.
704
25.4k
            if (!result) return {};
705
            // Replace the last node.subs.size() elements of results with the new result.
706
25.4k
            results.erase(results.end() - node.subs.size(), results.end());
707
25.4k
            results.push_back(std::move(*result));
708
25.4k
            stack.pop_back();
709
25.4k
        }
710
        // The final remaining results element is the root result, return it.
711
375
        assert(results.size() >= 1);
712
375
        CHECK_NONFATAL(results.size() == 1);
713
375
        return std::move(results[0]);
714
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
654
313
    {
655
        /** Entries of the explicit stack tracked in this algorithm. */
656
313
        struct StackElem
657
313
        {
658
313
            const Node& node; //!< The node being evaluated.
659
313
            size_t expanded; //!< How many children of this node have been expanded.
660
313
            State state; //!< The state for that node.
661
662
313
            StackElem(const Node& node_, size_t exp_, State&& state_) :
663
313
                node(node_), expanded(exp_), state(std::move(state_)) {}
664
313
        };
665
        /* Stack of tree nodes being explored. */
666
313
        std::vector<StackElem> stack;
667
        /* Results of subtrees so far. Their order and mapping to tree nodes
668
         * is implicitly defined by stack. */
669
313
        std::vector<Result> results;
670
313
        stack.emplace_back(*this, 0, std::move(root_state));
671
672
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
673
         * State variables are omitted for simplicity.
674
         *
675
         * First: stack=[(A,0)] results=[]
676
         *        stack=[(A,1),(B,0)] results=[]
677
         *        stack=[(A,1)] results=[B]
678
         *        stack=[(A,2),(C,0)] results=[B]
679
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
680
         *        stack=[(A,2),(C,1)] results=[B,D]
681
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
682
         *        stack=[(A,2),(C,2)] results=[B,D,E]
683
         *        stack=[(A,2)] results=[B,C]
684
         *        stack=[(A,3),(F,0)] results=[B,C]
685
         *        stack=[(A,3)] results=[B,C,F]
686
         * Final: stack=[] results=[A]
687
         */
688
46.5k
        while (stack.size()) {
689
46.1k
            const Node& node = stack.back().node;
690
46.1k
            if (stack.back().expanded < node.subs.size()) {
691
                /* We encounter a tree node with at least one unexpanded child.
692
                 * Expand it. By the time we hit this node again, the result of
693
                 * that child (and all earlier children) will be at the end of `results`. */
694
22.9k
                size_t child_index = stack.back().expanded++;
695
22.9k
                State child_state = downfn(stack.back().state, node, child_index);
696
22.9k
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
697
22.9k
                continue;
698
22.9k
            }
699
            // Invoke upfn with the last node.subs.size() elements of results as input.
700
46.1k
            assert(results.size() >= node.subs.size());
701
23.2k
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
702
23.2k
                std::span<Result>{results}.last(node.subs.size()))};
703
            // If evaluation returns std::nullopt, abort immediately.
704
23.2k
            if (!result) return {};
705
            // Replace the last node.subs.size() elements of results with the new result.
706
23.2k
            results.erase(results.end() - node.subs.size(), results.end());
707
23.2k
            results.push_back(std::move(*result));
708
23.2k
            stack.pop_back();
709
23.2k
        }
710
        // The final remaining results element is the root result, return it.
711
313
        assert(results.size() >= 1);
712
313
        CHECK_NONFATAL(results.size() == 1);
713
313
        return std::move(results[0]);
714
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
654
1
    {
655
        /** Entries of the explicit stack tracked in this algorithm. */
656
1
        struct StackElem
657
1
        {
658
1
            const Node& node; //!< The node being evaluated.
659
1
            size_t expanded; //!< How many children of this node have been expanded.
660
1
            State state; //!< The state for that node.
661
662
1
            StackElem(const Node& node_, size_t exp_, State&& state_) :
663
1
                node(node_), expanded(exp_), state(std::move(state_)) {}
664
1
        };
665
        /* Stack of tree nodes being explored. */
666
1
        std::vector<StackElem> stack;
667
        /* Results of subtrees so far. Their order and mapping to tree nodes
668
         * is implicitly defined by stack. */
669
1
        std::vector<Result> results;
670
1
        stack.emplace_back(*this, 0, std::move(root_state));
671
672
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
673
         * State variables are omitted for simplicity.
674
         *
675
         * First: stack=[(A,0)] results=[]
676
         *        stack=[(A,1),(B,0)] results=[]
677
         *        stack=[(A,1)] results=[B]
678
         *        stack=[(A,2),(C,0)] results=[B]
679
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
680
         *        stack=[(A,2),(C,1)] results=[B,D]
681
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
682
         *        stack=[(A,2),(C,2)] results=[B,D,E]
683
         *        stack=[(A,2)] results=[B,C]
684
         *        stack=[(A,3),(F,0)] results=[B,C]
685
         *        stack=[(A,3)] results=[B,C,F]
686
         * Final: stack=[] results=[A]
687
         */
688
14
        while (stack.size()) {
689
13
            const Node& node = stack.back().node;
690
13
            if (stack.back().expanded < node.subs.size()) {
691
                /* We encounter a tree node with at least one unexpanded child.
692
                 * Expand it. By the time we hit this node again, the result of
693
                 * that child (and all earlier children) will be at the end of `results`. */
694
6
                size_t child_index = stack.back().expanded++;
695
6
                State child_state = downfn(stack.back().state, node, child_index);
696
6
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
697
6
                continue;
698
6
            }
699
            // Invoke upfn with the last node.subs.size() elements of results as input.
700
13
            assert(results.size() >= node.subs.size());
701
7
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
702
7
                std::span<Result>{results}.last(node.subs.size()))};
703
            // If evaluation returns std::nullopt, abort immediately.
704
7
            if (!result) return {};
705
            // Replace the last node.subs.size() elements of results with the new result.
706
7
            results.erase(results.end() - node.subs.size(), results.end());
707
7
            results.push_back(std::move(*result));
708
7
            stack.pop_back();
709
7
        }
710
        // The final remaining results element is the root result, return it.
711
1
        assert(results.size() >= 1);
712
1
        CHECK_NONFATAL(results.size() == 1);
713
1
        return std::move(results[0]);
714
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
654
1
    {
655
        /** Entries of the explicit stack tracked in this algorithm. */
656
1
        struct StackElem
657
1
        {
658
1
            const Node& node; //!< The node being evaluated.
659
1
            size_t expanded; //!< How many children of this node have been expanded.
660
1
            State state; //!< The state for that node.
661
662
1
            StackElem(const Node& node_, size_t exp_, State&& state_) :
663
1
                node(node_), expanded(exp_), state(std::move(state_)) {}
664
1
        };
665
        /* Stack of tree nodes being explored. */
666
1
        std::vector<StackElem> stack;
667
        /* Results of subtrees so far. Their order and mapping to tree nodes
668
         * is implicitly defined by stack. */
669
1
        std::vector<Result> results;
670
1
        stack.emplace_back(*this, 0, std::move(root_state));
671
672
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
673
         * State variables are omitted for simplicity.
674
         *
675
         * First: stack=[(A,0)] results=[]
676
         *        stack=[(A,1),(B,0)] results=[]
677
         *        stack=[(A,1)] results=[B]
678
         *        stack=[(A,2),(C,0)] results=[B]
679
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
680
         *        stack=[(A,2),(C,1)] results=[B,D]
681
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
682
         *        stack=[(A,2),(C,2)] results=[B,D,E]
683
         *        stack=[(A,2)] results=[B,C]
684
         *        stack=[(A,3),(F,0)] results=[B,C]
685
         *        stack=[(A,3)] results=[B,C,F]
686
         * Final: stack=[] results=[A]
687
         */
688
8
        while (stack.size()) {
689
7
            const Node& node = stack.back().node;
690
7
            if (stack.back().expanded < node.subs.size()) {
691
                /* We encounter a tree node with at least one unexpanded child.
692
                 * Expand it. By the time we hit this node again, the result of
693
                 * that child (and all earlier children) will be at the end of `results`. */
694
3
                size_t child_index = stack.back().expanded++;
695
3
                State child_state = downfn(stack.back().state, node, child_index);
696
3
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
697
3
                continue;
698
3
            }
699
            // Invoke upfn with the last node.subs.size() elements of results as input.
700
7
            assert(results.size() >= node.subs.size());
701
4
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
702
4
                std::span<Result>{results}.last(node.subs.size()))};
703
            // If evaluation returns std::nullopt, abort immediately.
704
4
            if (!result) return {};
705
            // Replace the last node.subs.size() elements of results with the new result.
706
4
            results.erase(results.end() - node.subs.size(), results.end());
707
4
            results.push_back(std::move(*result));
708
4
            stack.pop_back();
709
4
        }
710
        // The final remaining results element is the root result, return it.
711
1
        assert(results.size() >= 1);
712
1
        CHECK_NONFATAL(results.size() == 1);
713
1
        return std::move(results[0]);
714
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
654
190
    {
655
        /** Entries of the explicit stack tracked in this algorithm. */
656
190
        struct StackElem
657
190
        {
658
190
            const Node& node; //!< The node being evaluated.
659
190
            size_t expanded; //!< How many children of this node have been expanded.
660
190
            State state; //!< The state for that node.
661
662
190
            StackElem(const Node& node_, size_t exp_, State&& state_) :
663
190
                node(node_), expanded(exp_), state(std::move(state_)) {}
664
190
        };
665
        /* Stack of tree nodes being explored. */
666
190
        std::vector<StackElem> stack;
667
        /* Results of subtrees so far. Their order and mapping to tree nodes
668
         * is implicitly defined by stack. */
669
190
        std::vector<Result> results;
670
190
        stack.emplace_back(*this, 0, std::move(root_state));
671
672
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
673
         * State variables are omitted for simplicity.
674
         *
675
         * First: stack=[(A,0)] results=[]
676
         *        stack=[(A,1),(B,0)] results=[]
677
         *        stack=[(A,1)] results=[B]
678
         *        stack=[(A,2),(C,0)] results=[B]
679
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
680
         *        stack=[(A,2),(C,1)] results=[B,D]
681
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
682
         *        stack=[(A,2),(C,2)] results=[B,D,E]
683
         *        stack=[(A,2)] results=[B,C]
684
         *        stack=[(A,3),(F,0)] results=[B,C]
685
         *        stack=[(A,3)] results=[B,C,F]
686
         * Final: stack=[] results=[A]
687
         */
688
1.06M
        while (stack.size()) {
689
1.06M
            const Node& node = stack.back().node;
690
1.06M
            if (stack.back().expanded < node.subs.size()) {
691
                /* We encounter a tree node with at least one unexpanded child.
692
                 * Expand it. By the time we hit this node again, the result of
693
                 * that child (and all earlier children) will be at the end of `results`. */
694
530k
                size_t child_index = stack.back().expanded++;
695
530k
                State child_state = downfn(stack.back().state, node, child_index);
696
530k
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
697
530k
                continue;
698
530k
            }
699
            // Invoke upfn with the last node.subs.size() elements of results as input.
700
1.06M
            assert(results.size() >= node.subs.size());
701
531k
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
702
531k
                std::span<Result>{results}.last(node.subs.size()))};
703
            // If evaluation returns std::nullopt, abort immediately.
704
531k
            if (!result) return {};
705
            // Replace the last node.subs.size() elements of results with the new result.
706
531k
            results.erase(results.end() - node.subs.size(), results.end());
707
531k
            results.push_back(std::move(*result));
708
531k
            stack.pop_back();
709
531k
        }
710
        // The final remaining results element is the root result, return it.
711
190
        assert(results.size() >= 1);
712
190
        CHECK_NONFATAL(results.size() == 1);
713
190
        return std::move(results[0]);
714
190
    }
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
654
783
    {
655
        /** Entries of the explicit stack tracked in this algorithm. */
656
783
        struct StackElem
657
783
        {
658
783
            const Node& node; //!< The node being evaluated.
659
783
            size_t expanded; //!< How many children of this node have been expanded.
660
783
            State state; //!< The state for that node.
661
662
783
            StackElem(const Node& node_, size_t exp_, State&& state_) :
663
783
                node(node_), expanded(exp_), state(std::move(state_)) {}
664
783
        };
665
        /* Stack of tree nodes being explored. */
666
783
        std::vector<StackElem> stack;
667
        /* Results of subtrees so far. Their order and mapping to tree nodes
668
         * is implicitly defined by stack. */
669
783
        std::vector<Result> results;
670
783
        stack.emplace_back(*this, 0, std::move(root_state));
671
672
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
673
         * State variables are omitted for simplicity.
674
         *
675
         * First: stack=[(A,0)] results=[]
676
         *        stack=[(A,1),(B,0)] results=[]
677
         *        stack=[(A,1)] results=[B]
678
         *        stack=[(A,2),(C,0)] results=[B]
679
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
680
         *        stack=[(A,2),(C,1)] results=[B,D]
681
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
682
         *        stack=[(A,2),(C,2)] results=[B,D,E]
683
         *        stack=[(A,2)] results=[B,C]
684
         *        stack=[(A,3),(F,0)] results=[B,C]
685
         *        stack=[(A,3)] results=[B,C,F]
686
         * Final: stack=[] results=[A]
687
         */
688
1.99M
        while (stack.size()) {
689
1.99M
            const Node& node = stack.back().node;
690
1.99M
            if (stack.back().expanded < node.subs.size()) {
691
                /* We encounter a tree node with at least one unexpanded child.
692
                 * Expand it. By the time we hit this node again, the result of
693
                 * that child (and all earlier children) will be at the end of `results`. */
694
994k
                size_t child_index = stack.back().expanded++;
695
994k
                State child_state = downfn(stack.back().state, node, child_index);
696
994k
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
697
994k
                continue;
698
994k
            }
699
            // Invoke upfn with the last node.subs.size() elements of results as input.
700
1.99M
            assert(results.size() >= node.subs.size());
701
995k
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
702
995k
                std::span<Result>{results}.last(node.subs.size()))};
703
            // If evaluation returns std::nullopt, abort immediately.
704
995k
            if (!result) return {};
705
            // Replace the last node.subs.size() elements of results with the new result.
706
995k
            results.erase(results.end() - node.subs.size(), results.end());
707
995k
            results.push_back(std::move(*result));
708
995k
            stack.pop_back();
709
995k
        }
710
        // The final remaining results element is the root result, return it.
711
783
        assert(results.size() >= 1);
712
783
        CHECK_NONFATAL(results.size() == 1);
713
783
        return std::move(results[0]);
714
783
    }
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
654
14
    {
655
        /** Entries of the explicit stack tracked in this algorithm. */
656
14
        struct StackElem
657
14
        {
658
14
            const Node& node; //!< The node being evaluated.
659
14
            size_t expanded; //!< How many children of this node have been expanded.
660
14
            State state; //!< The state for that node.
661
662
14
            StackElem(const Node& node_, size_t exp_, State&& state_) :
663
14
                node(node_), expanded(exp_), state(std::move(state_)) {}
664
14
        };
665
        /* Stack of tree nodes being explored. */
666
14
        std::vector<StackElem> stack;
667
        /* Results of subtrees so far. Their order and mapping to tree nodes
668
         * is implicitly defined by stack. */
669
14
        std::vector<Result> results;
670
14
        stack.emplace_back(*this, 0, std::move(root_state));
671
672
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
673
         * State variables are omitted for simplicity.
674
         *
675
         * First: stack=[(A,0)] results=[]
676
         *        stack=[(A,1),(B,0)] results=[]
677
         *        stack=[(A,1)] results=[B]
678
         *        stack=[(A,2),(C,0)] results=[B]
679
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
680
         *        stack=[(A,2),(C,1)] results=[B,D]
681
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
682
         *        stack=[(A,2),(C,2)] results=[B,D,E]
683
         *        stack=[(A,2)] results=[B,C]
684
         *        stack=[(A,3),(F,0)] results=[B,C]
685
         *        stack=[(A,3)] results=[B,C,F]
686
         * Final: stack=[] results=[A]
687
         */
688
214
        while (stack.size()) {
689
200
            const Node& node = stack.back().node;
690
200
            if (stack.back().expanded < node.subs.size()) {
691
                /* We encounter a tree node with at least one unexpanded child.
692
                 * Expand it. By the time we hit this node again, the result of
693
                 * that child (and all earlier children) will be at the end of `results`. */
694
93
                size_t child_index = stack.back().expanded++;
695
93
                State child_state = downfn(stack.back().state, node, child_index);
696
93
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
697
93
                continue;
698
93
            }
699
            // Invoke upfn with the last node.subs.size() elements of results as input.
700
200
            assert(results.size() >= node.subs.size());
701
107
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
702
107
                std::span<Result>{results}.last(node.subs.size()))};
703
            // If evaluation returns std::nullopt, abort immediately.
704
107
            if (!result) return {};
705
            // Replace the last node.subs.size() elements of results with the new result.
706
107
            results.erase(results.end() - node.subs.size(), results.end());
707
107
            results.push_back(std::move(*result));
708
107
            stack.pop_back();
709
107
        }
710
        // The final remaining results element is the root result, return it.
711
14
        assert(results.size() >= 1);
712
14
        CHECK_NONFATAL(results.size() == 1);
713
14
        return std::move(results[0]);
714
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
654
14
    {
655
        /** Entries of the explicit stack tracked in this algorithm. */
656
14
        struct StackElem
657
14
        {
658
14
            const Node& node; //!< The node being evaluated.
659
14
            size_t expanded; //!< How many children of this node have been expanded.
660
14
            State state; //!< The state for that node.
661
662
14
            StackElem(const Node& node_, size_t exp_, State&& state_) :
663
14
                node(node_), expanded(exp_), state(std::move(state_)) {}
664
14
        };
665
        /* Stack of tree nodes being explored. */
666
14
        std::vector<StackElem> stack;
667
        /* Results of subtrees so far. Their order and mapping to tree nodes
668
         * is implicitly defined by stack. */
669
14
        std::vector<Result> results;
670
14
        stack.emplace_back(*this, 0, std::move(root_state));
671
672
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
673
         * State variables are omitted for simplicity.
674
         *
675
         * First: stack=[(A,0)] results=[]
676
         *        stack=[(A,1),(B,0)] results=[]
677
         *        stack=[(A,1)] results=[B]
678
         *        stack=[(A,2),(C,0)] results=[B]
679
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
680
         *        stack=[(A,2),(C,1)] results=[B,D]
681
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
682
         *        stack=[(A,2),(C,2)] results=[B,D,E]
683
         *        stack=[(A,2)] results=[B,C]
684
         *        stack=[(A,3),(F,0)] results=[B,C]
685
         *        stack=[(A,3)] results=[B,C,F]
686
         * Final: stack=[] results=[A]
687
         */
688
158
        while (stack.size()) {
689
144
            const Node& node = stack.back().node;
690
144
            if (stack.back().expanded < node.subs.size()) {
691
                /* We encounter a tree node with at least one unexpanded child.
692
                 * Expand it. By the time we hit this node again, the result of
693
                 * that child (and all earlier children) will be at the end of `results`. */
694
65
                size_t child_index = stack.back().expanded++;
695
65
                State child_state = downfn(stack.back().state, node, child_index);
696
65
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
697
65
                continue;
698
65
            }
699
            // Invoke upfn with the last node.subs.size() elements of results as input.
700
144
            assert(results.size() >= node.subs.size());
701
79
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
702
79
                std::span<Result>{results}.last(node.subs.size()))};
703
            // If evaluation returns std::nullopt, abort immediately.
704
79
            if (!result) return {};
705
            // Replace the last node.subs.size() elements of results with the new result.
706
79
            results.erase(results.end() - node.subs.size(), results.end());
707
79
            results.push_back(std::move(*result));
708
79
            stack.pop_back();
709
79
        }
710
        // The final remaining results element is the root result, return it.
711
14
        assert(results.size() >= 1);
712
14
        CHECK_NONFATAL(results.size() == 1);
713
14
        return std::move(results[0]);
714
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
654
1.47k
    {
655
        /** Entries of the explicit stack tracked in this algorithm. */
656
1.47k
        struct StackElem
657
1.47k
        {
658
1.47k
            const Node& node; //!< The node being evaluated.
659
1.47k
            size_t expanded; //!< How many children of this node have been expanded.
660
1.47k
            State state; //!< The state for that node.
661
662
1.47k
            StackElem(const Node& node_, size_t exp_, State&& state_) :
663
1.47k
                node(node_), expanded(exp_), state(std::move(state_)) {}
664
1.47k
        };
665
        /* Stack of tree nodes being explored. */
666
1.47k
        std::vector<StackElem> stack;
667
        /* Results of subtrees so far. Their order and mapping to tree nodes
668
         * is implicitly defined by stack. */
669
1.47k
        std::vector<Result> results;
670
1.47k
        stack.emplace_back(*this, 0, std::move(root_state));
671
672
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
673
         * State variables are omitted for simplicity.
674
         *
675
         * First: stack=[(A,0)] results=[]
676
         *        stack=[(A,1),(B,0)] results=[]
677
         *        stack=[(A,1)] results=[B]
678
         *        stack=[(A,2),(C,0)] results=[B]
679
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
680
         *        stack=[(A,2),(C,1)] results=[B,D]
681
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
682
         *        stack=[(A,2),(C,2)] results=[B,D,E]
683
         *        stack=[(A,2)] results=[B,C]
684
         *        stack=[(A,3),(F,0)] results=[B,C]
685
         *        stack=[(A,3)] results=[B,C,F]
686
         * Final: stack=[] results=[A]
687
         */
688
3.32M
        while (stack.size()) {
689
3.32M
            const Node& node = stack.back().node;
690
3.32M
            if (stack.back().expanded < node.subs.size()) {
691
                /* We encounter a tree node with at least one unexpanded child.
692
                 * Expand it. By the time we hit this node again, the result of
693
                 * that child (and all earlier children) will be at the end of `results`. */
694
1.66M
                size_t child_index = stack.back().expanded++;
695
1.66M
                State child_state = downfn(stack.back().state, node, child_index);
696
1.66M
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
697
1.66M
                continue;
698
1.66M
            }
699
            // Invoke upfn with the last node.subs.size() elements of results as input.
700
3.32M
            assert(results.size() >= node.subs.size());
701
1.66M
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
702
1.66M
                std::span<Result>{results}.last(node.subs.size()))};
703
            // If evaluation returns std::nullopt, abort immediately.
704
1.66M
            if (!result) return {};
705
            // Replace the last node.subs.size() elements of results with the new result.
706
1.66M
            results.erase(results.end() - node.subs.size(), results.end());
707
1.66M
            results.push_back(std::move(*result));
708
1.66M
            stack.pop_back();
709
1.66M
        }
710
        // The final remaining results element is the root result, return it.
711
1.47k
        assert(results.size() >= 1);
712
1.47k
        CHECK_NONFATAL(results.size() == 1);
713
1.47k
        return std::move(results[0]);
714
1.47k
    }
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
654
1.08k
    {
655
        /** Entries of the explicit stack tracked in this algorithm. */
656
1.08k
        struct StackElem
657
1.08k
        {
658
1.08k
            const Node& node; //!< The node being evaluated.
659
1.08k
            size_t expanded; //!< How many children of this node have been expanded.
660
1.08k
            State state; //!< The state for that node.
661
662
1.08k
            StackElem(const Node& node_, size_t exp_, State&& state_) :
663
1.08k
                node(node_), expanded(exp_), state(std::move(state_)) {}
664
1.08k
        };
665
        /* Stack of tree nodes being explored. */
666
1.08k
        std::vector<StackElem> stack;
667
        /* Results of subtrees so far. Their order and mapping to tree nodes
668
         * is implicitly defined by stack. */
669
1.08k
        std::vector<Result> results;
670
1.08k
        stack.emplace_back(*this, 0, std::move(root_state));
671
672
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
673
         * State variables are omitted for simplicity.
674
         *
675
         * First: stack=[(A,0)] results=[]
676
         *        stack=[(A,1),(B,0)] results=[]
677
         *        stack=[(A,1)] results=[B]
678
         *        stack=[(A,2),(C,0)] results=[B]
679
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
680
         *        stack=[(A,2),(C,1)] results=[B,D]
681
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
682
         *        stack=[(A,2),(C,2)] results=[B,D,E]
683
         *        stack=[(A,2)] results=[B,C]
684
         *        stack=[(A,3),(F,0)] results=[B,C]
685
         *        stack=[(A,3)] results=[B,C,F]
686
         * Final: stack=[] results=[A]
687
         */
688
5.95M
        while (stack.size()) {
689
5.95M
            const Node& node = stack.back().node;
690
5.95M
            if (stack.back().expanded < node.subs.size()) {
691
                /* We encounter a tree node with at least one unexpanded child.
692
                 * Expand it. By the time we hit this node again, the result of
693
                 * that child (and all earlier children) will be at the end of `results`. */
694
2.97M
                size_t child_index = stack.back().expanded++;
695
2.97M
                State child_state = downfn(stack.back().state, node, child_index);
696
2.97M
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
697
2.97M
                continue;
698
2.97M
            }
699
            // Invoke upfn with the last node.subs.size() elements of results as input.
700
5.95M
            assert(results.size() >= node.subs.size());
701
2.97M
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
702
2.97M
                std::span<Result>{results}.last(node.subs.size()))};
703
            // If evaluation returns std::nullopt, abort immediately.
704
2.97M
            if (!result) return {};
705
            // Replace the last node.subs.size() elements of results with the new result.
706
2.97M
            results.erase(results.end() - node.subs.size(), results.end());
707
2.97M
            results.push_back(std::move(*result));
708
2.97M
            stack.pop_back();
709
2.97M
        }
710
        // The final remaining results element is the root result, return it.
711
1.08k
        assert(results.size() >= 1);
712
1.08k
        CHECK_NONFATAL(results.size() == 1);
713
1.08k
        return std::move(results[0]);
714
1.08k
    }
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
654
3.16k
    {
655
        /** Entries of the explicit stack tracked in this algorithm. */
656
3.16k
        struct StackElem
657
3.16k
        {
658
3.16k
            const Node& node; //!< The node being evaluated.
659
3.16k
            size_t expanded; //!< How many children of this node have been expanded.
660
3.16k
            State state; //!< The state for that node.
661
662
3.16k
            StackElem(const Node& node_, size_t exp_, State&& state_) :
663
3.16k
                node(node_), expanded(exp_), state(std::move(state_)) {}
664
3.16k
        };
665
        /* Stack of tree nodes being explored. */
666
3.16k
        std::vector<StackElem> stack;
667
        /* Results of subtrees so far. Their order and mapping to tree nodes
668
         * is implicitly defined by stack. */
669
3.16k
        std::vector<Result> results;
670
3.16k
        stack.emplace_back(*this, 0, std::move(root_state));
671
672
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
673
         * State variables are omitted for simplicity.
674
         *
675
         * First: stack=[(A,0)] results=[]
676
         *        stack=[(A,1),(B,0)] results=[]
677
         *        stack=[(A,1)] results=[B]
678
         *        stack=[(A,2),(C,0)] results=[B]
679
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
680
         *        stack=[(A,2),(C,1)] results=[B,D]
681
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
682
         *        stack=[(A,2),(C,2)] results=[B,D,E]
683
         *        stack=[(A,2)] results=[B,C]
684
         *        stack=[(A,3),(F,0)] results=[B,C]
685
         *        stack=[(A,3)] results=[B,C,F]
686
         * Final: stack=[] results=[A]
687
         */
688
14.5M
        while (stack.size()) {
689
14.5M
            const Node& node = stack.back().node;
690
14.5M
            if (stack.back().expanded < node.subs.size()) {
691
                /* We encounter a tree node with at least one unexpanded child.
692
                 * Expand it. By the time we hit this node again, the result of
693
                 * that child (and all earlier children) will be at the end of `results`. */
694
7.25M
                size_t child_index = stack.back().expanded++;
695
7.25M
                State child_state = downfn(stack.back().state, node, child_index);
696
7.25M
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
697
7.25M
                continue;
698
7.25M
            }
699
            // Invoke upfn with the last node.subs.size() elements of results as input.
700
14.5M
            assert(results.size() >= node.subs.size());
701
7.25M
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
702
7.25M
                std::span<Result>{results}.last(node.subs.size()))};
703
            // If evaluation returns std::nullopt, abort immediately.
704
7.25M
            if (!result) return {};
705
            // Replace the last node.subs.size() elements of results with the new result.
706
7.25M
            results.erase(results.end() - node.subs.size(), results.end());
707
7.25M
            results.push_back(std::move(*result));
708
7.25M
            stack.pop_back();
709
7.25M
        }
710
        // The final remaining results element is the root result, return it.
711
3.16k
        assert(results.size() >= 1);
712
3.16k
        CHECK_NONFATAL(results.size() == 1);
713
3.16k
        return std::move(results[0]);
714
3.16k
    }
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
654
3.16k
    {
655
        /** Entries of the explicit stack tracked in this algorithm. */
656
3.16k
        struct StackElem
657
3.16k
        {
658
3.16k
            const Node& node; //!< The node being evaluated.
659
3.16k
            size_t expanded; //!< How many children of this node have been expanded.
660
3.16k
            State state; //!< The state for that node.
661
662
3.16k
            StackElem(const Node& node_, size_t exp_, State&& state_) :
663
3.16k
                node(node_), expanded(exp_), state(std::move(state_)) {}
664
3.16k
        };
665
        /* Stack of tree nodes being explored. */
666
3.16k
        std::vector<StackElem> stack;
667
        /* Results of subtrees so far. Their order and mapping to tree nodes
668
         * is implicitly defined by stack. */
669
3.16k
        std::vector<Result> results;
670
3.16k
        stack.emplace_back(*this, 0, std::move(root_state));
671
672
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
673
         * State variables are omitted for simplicity.
674
         *
675
         * First: stack=[(A,0)] results=[]
676
         *        stack=[(A,1),(B,0)] results=[]
677
         *        stack=[(A,1)] results=[B]
678
         *        stack=[(A,2),(C,0)] results=[B]
679
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
680
         *        stack=[(A,2),(C,1)] results=[B,D]
681
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
682
         *        stack=[(A,2),(C,2)] results=[B,D,E]
683
         *        stack=[(A,2)] results=[B,C]
684
         *        stack=[(A,3),(F,0)] results=[B,C]
685
         *        stack=[(A,3)] results=[B,C,F]
686
         * Final: stack=[] results=[A]
687
         */
688
14.5M
        while (stack.size()) {
689
14.5M
            const Node& node = stack.back().node;
690
14.5M
            if (stack.back().expanded < node.subs.size()) {
691
                /* We encounter a tree node with at least one unexpanded child.
692
                 * Expand it. By the time we hit this node again, the result of
693
                 * that child (and all earlier children) will be at the end of `results`. */
694
7.25M
                size_t child_index = stack.back().expanded++;
695
7.25M
                State child_state = downfn(stack.back().state, node, child_index);
696
7.25M
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
697
7.25M
                continue;
698
7.25M
            }
699
            // Invoke upfn with the last node.subs.size() elements of results as input.
700
14.5M
            assert(results.size() >= node.subs.size());
701
7.25M
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
702
7.25M
                std::span<Result>{results}.last(node.subs.size()))};
703
            // If evaluation returns std::nullopt, abort immediately.
704
7.25M
            if (!result) return {};
705
            // Replace the last node.subs.size() elements of results with the new result.
706
7.25M
            results.erase(results.end() - node.subs.size(), results.end());
707
7.25M
            results.push_back(std::move(*result));
708
7.25M
            stack.pop_back();
709
7.25M
        }
710
        // The final remaining results element is the root result, return it.
711
3.16k
        assert(results.size() >= 1);
712
3.16k
        CHECK_NONFATAL(results.size() == 1);
713
3.16k
        return std::move(results[0]);
714
3.16k
    }
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
654
234
    {
655
        /** Entries of the explicit stack tracked in this algorithm. */
656
234
        struct StackElem
657
234
        {
658
234
            const Node& node; //!< The node being evaluated.
659
234
            size_t expanded; //!< How many children of this node have been expanded.
660
234
            State state; //!< The state for that node.
661
662
234
            StackElem(const Node& node_, size_t exp_, State&& state_) :
663
234
                node(node_), expanded(exp_), state(std::move(state_)) {}
664
234
        };
665
        /* Stack of tree nodes being explored. */
666
234
        std::vector<StackElem> stack;
667
        /* Results of subtrees so far. Their order and mapping to tree nodes
668
         * is implicitly defined by stack. */
669
234
        std::vector<Result> results;
670
234
        stack.emplace_back(*this, 0, std::move(root_state));
671
672
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
673
         * State variables are omitted for simplicity.
674
         *
675
         * First: stack=[(A,0)] results=[]
676
         *        stack=[(A,1),(B,0)] results=[]
677
         *        stack=[(A,1)] results=[B]
678
         *        stack=[(A,2),(C,0)] results=[B]
679
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
680
         *        stack=[(A,2),(C,1)] results=[B,D]
681
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
682
         *        stack=[(A,2),(C,2)] results=[B,D,E]
683
         *        stack=[(A,2)] results=[B,C]
684
         *        stack=[(A,3),(F,0)] results=[B,C]
685
         *        stack=[(A,3)] results=[B,C,F]
686
         * Final: stack=[] results=[A]
687
         */
688
6.47k
        while (stack.size()) {
689
6.24k
            const Node& node = stack.back().node;
690
6.24k
            if (stack.back().expanded < node.subs.size()) {
691
                /* We encounter a tree node with at least one unexpanded child.
692
                 * Expand it. By the time we hit this node again, the result of
693
                 * that child (and all earlier children) will be at the end of `results`. */
694
3.00k
                size_t child_index = stack.back().expanded++;
695
3.00k
                State child_state = downfn(stack.back().state, node, child_index);
696
3.00k
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
697
3.00k
                continue;
698
3.00k
            }
699
            // Invoke upfn with the last node.subs.size() elements of results as input.
700
6.24k
            assert(results.size() >= node.subs.size());
701
3.23k
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
702
3.23k
                std::span<Result>{results}.last(node.subs.size()))};
703
            // If evaluation returns std::nullopt, abort immediately.
704
3.23k
            if (!result) return {};
705
            // Replace the last node.subs.size() elements of results with the new result.
706
3.23k
            results.erase(results.end() - node.subs.size(), results.end());
707
3.23k
            results.push_back(std::move(*result));
708
3.23k
            stack.pop_back();
709
3.23k
        }
710
        // The final remaining results element is the root result, return it.
711
234
        assert(results.size() >= 1);
712
234
        CHECK_NONFATAL(results.size() == 1);
713
234
        return std::move(results[0]);
714
234
    }
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
654
234
    {
655
        /** Entries of the explicit stack tracked in this algorithm. */
656
234
        struct StackElem
657
234
        {
658
234
            const Node& node; //!< The node being evaluated.
659
234
            size_t expanded; //!< How many children of this node have been expanded.
660
234
            State state; //!< The state for that node.
661
662
234
            StackElem(const Node& node_, size_t exp_, State&& state_) :
663
234
                node(node_), expanded(exp_), state(std::move(state_)) {}
664
234
        };
665
        /* Stack of tree nodes being explored. */
666
234
        std::vector<StackElem> stack;
667
        /* Results of subtrees so far. Their order and mapping to tree nodes
668
         * is implicitly defined by stack. */
669
234
        std::vector<Result> results;
670
234
        stack.emplace_back(*this, 0, std::move(root_state));
671
672
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
673
         * State variables are omitted for simplicity.
674
         *
675
         * First: stack=[(A,0)] results=[]
676
         *        stack=[(A,1),(B,0)] results=[]
677
         *        stack=[(A,1)] results=[B]
678
         *        stack=[(A,2),(C,0)] results=[B]
679
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
680
         *        stack=[(A,2),(C,1)] results=[B,D]
681
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
682
         *        stack=[(A,2),(C,2)] results=[B,D,E]
683
         *        stack=[(A,2)] results=[B,C]
684
         *        stack=[(A,3),(F,0)] results=[B,C]
685
         *        stack=[(A,3)] results=[B,C,F]
686
         * Final: stack=[] results=[A]
687
         */
688
6.47k
        while (stack.size()) {
689
6.24k
            const Node& node = stack.back().node;
690
6.24k
            if (stack.back().expanded < node.subs.size()) {
691
                /* We encounter a tree node with at least one unexpanded child.
692
                 * Expand it. By the time we hit this node again, the result of
693
                 * that child (and all earlier children) will be at the end of `results`. */
694
3.00k
                size_t child_index = stack.back().expanded++;
695
3.00k
                State child_state = downfn(stack.back().state, node, child_index);
696
3.00k
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
697
3.00k
                continue;
698
3.00k
            }
699
            // Invoke upfn with the last node.subs.size() elements of results as input.
700
6.24k
            assert(results.size() >= node.subs.size());
701
3.23k
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
702
3.23k
                std::span<Result>{results}.last(node.subs.size()))};
703
            // If evaluation returns std::nullopt, abort immediately.
704
3.23k
            if (!result) return {};
705
            // Replace the last node.subs.size() elements of results with the new result.
706
3.23k
            results.erase(results.end() - node.subs.size(), results.end());
707
3.23k
            results.push_back(std::move(*result));
708
3.23k
            stack.pop_back();
709
3.23k
        }
710
        // The final remaining results element is the root result, return it.
711
234
        assert(results.size() >= 1);
712
234
        CHECK_NONFATAL(results.size() == 1);
713
234
        return std::move(results[0]);
714
234
    }
715
716
    /** Like TreeEvalMaybe, but without downfn or State type.
717
     * upfn takes (const Node&, std::span<Result>) and returns std::optional<Result>. */
718
    template<typename Result, typename UpFn>
719
    std::optional<Result> TreeEvalMaybe(UpFn upfn) const
720
    {
721
        struct DummyState {};
722
        return TreeEvalMaybe<Result>(DummyState{},
723
            [](DummyState, const Node&, size_t) { return DummyState{}; },
724
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
725
                return upfn(node, subs);
726
            }
727
        );
728
    }
729
730
    /** Like TreeEvalMaybe, but always produces a result. upfn must return Result. */
731
    template<typename Result, typename State, typename DownFn, typename UpFn>
732
    Result TreeEval(State root_state, DownFn&& downfn, UpFn upfn) const
733
1.84k
    {
734
        // Invoke TreeEvalMaybe with upfn wrapped to return std::optional<Result>, and then
735
        // unconditionally dereference the result (it cannot be std::nullopt).
736
1.84k
        return std::move(*TreeEvalMaybe<Result>(std::move(root_state),
737
1.84k
            std::forward<DownFn>(downfn),
738
1.68M
            [&upfn](State&& state, const Node& node, std::span<Result> subs) {
739
1.68M
                Result res{upfn(std::move(state), node, subs)};
740
1.68M
                return std::optional<Result>(std::move(res));
741
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
738
25.4k
            [&upfn](State&& state, const Node& node, std::span<Result> subs) {
739
25.4k
                Result res{upfn(std::move(state), node, subs)};
740
25.4k
                return std::optional<Result>(std::move(res));
741
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
738
1.66M
            [&upfn](State&& state, const Node& node, std::span<Result> subs) {
739
1.66M
                Result res{upfn(std::move(state), node, subs)};
740
1.66M
                return std::optional<Result>(std::move(res));
741
1.66M
            }
742
1.84k
        ));
743
1.84k
    }
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
733
375
    {
734
        // Invoke TreeEvalMaybe with upfn wrapped to return std::optional<Result>, and then
735
        // unconditionally dereference the result (it cannot be std::nullopt).
736
375
        return std::move(*TreeEvalMaybe<Result>(std::move(root_state),
737
375
            std::forward<DownFn>(downfn),
738
375
            [&upfn](State&& state, const Node& node, std::span<Result> subs) {
739
375
                Result res{upfn(std::move(state), node, subs)};
740
375
                return std::optional<Result>(std::move(res));
741
375
            }
742
375
        ));
743
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
733
1.47k
    {
734
        // Invoke TreeEvalMaybe with upfn wrapped to return std::optional<Result>, and then
735
        // unconditionally dereference the result (it cannot be std::nullopt).
736
1.47k
        return std::move(*TreeEvalMaybe<Result>(std::move(root_state),
737
1.47k
            std::forward<DownFn>(downfn),
738
1.47k
            [&upfn](State&& state, const Node& node, std::span<Result> subs) {
739
1.47k
                Result res{upfn(std::move(state), node, subs)};
740
1.47k
                return std::optional<Result>(std::move(res));
741
1.47k
            }
742
1.47k
        ));
743
1.47k
    }
744
745
    /** Like TreeEval, but without downfn or State type.
746
     *  upfn takes (const Node&, std::span<Result>) and returns Result. */
747
    template<typename Result, typename UpFn>
748
    Result TreeEval(UpFn upfn) const
749
13.2k
    {
750
13.2k
        struct DummyState {};
751
13.2k
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
752
17.6M
            [](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
752
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
752
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
752
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
752
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
752
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
752
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
752
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
752
7.25M
            [](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
752
7.25M
            [](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
752
3.00k
            [](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
752
3.00k
            [](DummyState, const Node&, size_t) { return DummyState{}; },
753
17.7M
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
754
17.7M
                Result res{upfn(node, subs)};
755
17.7M
                return std::optional<Result>(std::move(res));
756
17.7M
            }
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
753
1.61M
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
754
1.61M
                Result res{upfn(node, subs)};
755
1.61M
                return std::optional<Result>(std::move(res));
756
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
753
25.4k
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
754
25.4k
                Result res{upfn(node, subs)};
755
25.4k
                return std::optional<Result>(std::move(res));
756
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
753
23.2k
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
754
23.2k
                Result res{upfn(node, subs)};
755
23.2k
                return std::optional<Result>(std::move(res));
756
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
753
7
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
754
7
                Result res{upfn(node, subs)};
755
7
                return std::optional<Result>(std::move(res));
756
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
753
531k
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
754
531k
                Result res{upfn(node, subs)};
755
531k
                return std::optional<Result>(std::move(res));
756
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
753
995k
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
754
995k
                Result res{upfn(node, subs)};
755
995k
                return std::optional<Result>(std::move(res));
756
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
753
107
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
754
107
                Result res{upfn(node, subs)};
755
107
                return std::optional<Result>(std::move(res));
756
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
753
7.25M
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
754
7.25M
                Result res{upfn(node, subs)};
755
7.25M
                return std::optional<Result>(std::move(res));
756
7.25M
            }
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
753
7.25M
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
754
7.25M
                Result res{upfn(node, subs)};
755
7.25M
                return std::optional<Result>(std::move(res));
756
7.25M
            }
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
753
3.23k
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
754
3.23k
                Result res{upfn(node, subs)};
755
3.23k
                return std::optional<Result>(std::move(res));
756
3.23k
            }
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
753
3.23k
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
754
3.23k
                Result res{upfn(node, subs)};
755
3.23k
                return std::optional<Result>(std::move(res));
756
3.23k
            }
757
13.2k
        ));
758
13.2k
    }
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
749
4.82k
    {
750
4.82k
        struct DummyState {};
751
4.82k
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
752
4.82k
            [](DummyState, const Node&, size_t) { return DummyState{}; },
753
4.82k
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
754
4.82k
                Result res{upfn(node, subs)};
755
4.82k
                return std::optional<Result>(std::move(res));
756
4.82k
            }
757
4.82k
        ));
758
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
749
375
    {
750
375
        struct DummyState {};
751
375
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
752
375
            [](DummyState, const Node&, size_t) { return DummyState{}; },
753
375
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
754
375
                Result res{upfn(node, subs)};
755
375
                return std::optional<Result>(std::move(res));
756
375
            }
757
375
        ));
758
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
749
313
    {
750
313
        struct DummyState {};
751
313
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
752
313
            [](DummyState, const Node&, size_t) { return DummyState{}; },
753
313
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
754
313
                Result res{upfn(node, subs)};
755
313
                return std::optional<Result>(std::move(res));
756
313
            }
757
313
        ));
758
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
749
1
    {
750
1
        struct DummyState {};
751
1
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
752
1
            [](DummyState, const Node&, size_t) { return DummyState{}; },
753
1
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
754
1
                Result res{upfn(node, subs)};
755
1
                return std::optional<Result>(std::move(res));
756
1
            }
757
1
        ));
758
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
749
190
    {
750
190
        struct DummyState {};
751
190
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
752
190
            [](DummyState, const Node&, size_t) { return DummyState{}; },
753
190
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
754
190
                Result res{upfn(node, subs)};
755
190
                return std::optional<Result>(std::move(res));
756
190
            }
757
190
        ));
758
190
    }
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
749
783
    {
750
783
        struct DummyState {};
751
783
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
752
783
            [](DummyState, const Node&, size_t) { return DummyState{}; },
753
783
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
754
783
                Result res{upfn(node, subs)};
755
783
                return std::optional<Result>(std::move(res));
756
783
            }
757
783
        ));
758
783
    }
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
749
14
    {
750
14
        struct DummyState {};
751
14
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
752
14
            [](DummyState, const Node&, size_t) { return DummyState{}; },
753
14
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
754
14
                Result res{upfn(node, subs)};
755
14
                return std::optional<Result>(std::move(res));
756
14
            }
757
14
        ));
758
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
749
3.16k
    {
750
3.16k
        struct DummyState {};
751
3.16k
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
752
3.16k
            [](DummyState, const Node&, size_t) { return DummyState{}; },
753
3.16k
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
754
3.16k
                Result res{upfn(node, subs)};
755
3.16k
                return std::optional<Result>(std::move(res));
756
3.16k
            }
757
3.16k
        ));
758
3.16k
    }
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
749
3.16k
    {
750
3.16k
        struct DummyState {};
751
3.16k
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
752
3.16k
            [](DummyState, const Node&, size_t) { return DummyState{}; },
753
3.16k
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
754
3.16k
                Result res{upfn(node, subs)};
755
3.16k
                return std::optional<Result>(std::move(res));
756
3.16k
            }
757
3.16k
        ));
758
3.16k
    }
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
749
234
    {
750
234
        struct DummyState {};
751
234
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
752
234
            [](DummyState, const Node&, size_t) { return DummyState{}; },
753
234
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
754
234
                Result res{upfn(node, subs)};
755
234
                return std::optional<Result>(std::move(res));
756
234
            }
757
234
        ));
758
234
    }
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
749
234
    {
750
234
        struct DummyState {};
751
234
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
752
234
            [](DummyState, const Node&, size_t) { return DummyState{}; },
753
234
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
754
234
                Result res{upfn(node, subs)};
755
234
                return std::optional<Result>(std::move(res));
756
234
            }
757
234
        ));
758
234
    }
759
760
    /** Compare two miniscript subtrees, using a non-recursive algorithm. */
761
    friend int Compare(const Node<Key>& node1, const Node<Key>& node2)
762
    {
763
        std::vector<std::pair<const Node<Key>&, const Node<Key>&>> queue;
764
        queue.emplace_back(node1, node2);
765
        while (!queue.empty()) {
766
            const auto& [a, b] = queue.back();
767
            queue.pop_back();
768
            if (std::tie(a.fragment, a.k, a.keys, a.data) < std::tie(b.fragment, b.k, b.keys, b.data)) return -1;
769
            if (std::tie(b.fragment, b.k, b.keys, b.data) < std::tie(a.fragment, a.k, a.keys, a.data)) return 1;
770
            if (a.subs.size() < b.subs.size()) return -1;
771
            if (b.subs.size() < a.subs.size()) return 1;
772
            size_t n = a.subs.size();
773
            for (size_t i = 0; i < n; ++i) {
774
                queue.emplace_back(a.subs[n - 1 - i], b.subs[n - 1 - i]);
775
            }
776
        }
777
        return 0;
778
    }
779
780
    //! Compute the type for this miniscript.
781
9.01M
    Type CalcType() const {
782
9.01M
        using namespace internal;
783
784
        // THRESH has a variable number of subexpressions
785
9.01M
        std::vector<Type> sub_types;
786
9.01M
        if (fragment == Fragment::THRESH) {
787
1.57k
            for (const auto& sub : subs) sub_types.push_back(sub.GetType());
788
410
        }
789
        // All other nodes than THRESH can be computed just from the types of the 0-3 subexpressions.
790
9.01M
        Type x = subs.size() > 0 ? subs[0].GetType() : ""_mst;
791
9.01M
        Type y = subs.size() > 1 ? subs[1].GetType() : ""_mst;
792
9.01M
        Type z = subs.size() > 2 ? subs[2].GetType() : ""_mst;
793
794
9.01M
        return SanitizeType(ComputeType(fragment, x, y, z, sub_types, k, data.size(), subs.size(), keys.size(), m_script_ctx));
795
9.01M
    }
miniscript::Node<CPubKey>::CalcType() const
Line
Count
Source
781
28.5k
    Type CalcType() const {
782
28.5k
        using namespace internal;
783
784
        // THRESH has a variable number of subexpressions
785
28.5k
        std::vector<Type> sub_types;
786
28.5k
        if (fragment == Fragment::THRESH) {
787
679
            for (const auto& sub : subs) sub_types.push_back(sub.GetType());
788
140
        }
789
        // All other nodes than THRESH can be computed just from the types of the 0-3 subexpressions.
790
28.5k
        Type x = subs.size() > 0 ? subs[0].GetType() : ""_mst;
791
28.5k
        Type y = subs.size() > 1 ? subs[1].GetType() : ""_mst;
792
28.5k
        Type z = subs.size() > 2 ? subs[2].GetType() : ""_mst;
793
794
28.5k
        return SanitizeType(ComputeType(fragment, x, y, z, sub_types, k, data.size(), subs.size(), keys.size(), m_script_ctx));
795
28.5k
    }
miniscript::Node<unsigned int>::CalcType() const
Line
Count
Source
781
1.72M
    Type CalcType() const {
782
1.72M
        using namespace internal;
783
784
        // THRESH has a variable number of subexpressions
785
1.72M
        std::vector<Type> sub_types;
786
1.72M
        if (fragment == Fragment::THRESH) {
787
814
            for (const auto& sub : subs) sub_types.push_back(sub.GetType());
788
242
        }
789
        // All other nodes than THRESH can be computed just from the types of the 0-3 subexpressions.
790
1.72M
        Type x = subs.size() > 0 ? subs[0].GetType() : ""_mst;
791
1.72M
        Type y = subs.size() > 1 ? subs[1].GetType() : ""_mst;
792
1.72M
        Type z = subs.size() > 2 ? subs[2].GetType() : ""_mst;
793
794
1.72M
        return SanitizeType(ComputeType(fragment, x, y, z, sub_types, k, data.size(), subs.size(), keys.size(), m_script_ctx));
795
1.72M
    }
miniscript::Node<XOnlyPubKey>::CalcType() const
Line
Count
Source
781
7.25M
    Type CalcType() const {
782
7.25M
        using namespace internal;
783
784
        // THRESH has a variable number of subexpressions
785
7.25M
        std::vector<Type> sub_types;
786
7.25M
        if (fragment == Fragment::THRESH) {
787
84
            for (const auto& sub : subs) sub_types.push_back(sub.GetType());
788
28
        }
789
        // All other nodes than THRESH can be computed just from the types of the 0-3 subexpressions.
790
7.25M
        Type x = subs.size() > 0 ? subs[0].GetType() : ""_mst;
791
7.25M
        Type y = subs.size() > 1 ? subs[1].GetType() : ""_mst;
792
7.25M
        Type z = subs.size() > 2 ? subs[2].GetType() : ""_mst;
793
794
7.25M
        return SanitizeType(ComputeType(fragment, x, y, z, sub_types, k, data.size(), subs.size(), keys.size(), m_script_ctx));
795
7.25M
    }
796
797
public:
798
    template<typename Ctx>
799
    CScript ToScript(const Ctx& ctx) const
800
1.84k
    {
801
        // To construct the CScript for a Miniscript object, we use the TreeEval algorithm.
802
        // The State is a boolean: whether or not the node's script expansion is followed
803
        // by an OP_VERIFY (which may need to be combined with the last script opcode).
804
1.68M
        auto downfn = [](bool verify, const Node& node, size_t index) {
805
            // For WRAP_V, the subexpression is certainly followed by OP_VERIFY.
806
1.68M
            if (node.fragment == Fragment::WRAP_V) return true;
807
            // The subexpression of WRAP_S, and the last subexpression of AND_V
808
            // inherit the followed-by-OP_VERIFY property from the parent.
809
1.68M
            if (node.fragment == Fragment::WRAP_S ||
810
1.68M
                (node.fragment == Fragment::AND_V && index == 1)) return verify;
811
1.68M
            return false;
812
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
804
25.0k
        auto downfn = [](bool verify, const Node& node, size_t index) {
805
            // For WRAP_V, the subexpression is certainly followed by OP_VERIFY.
806
25.0k
            if (node.fragment == Fragment::WRAP_V) return true;
807
            // The subexpression of WRAP_S, and the last subexpression of AND_V
808
            // inherit the followed-by-OP_VERIFY property from the parent.
809
24.7k
            if (node.fragment == Fragment::WRAP_S ||
810
24.7k
                (node.fragment == Fragment::AND_V && index == 1)) return verify;
811
24.5k
            return false;
812
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
804
1.66M
        auto downfn = [](bool verify, const Node& node, size_t index) {
805
            // For WRAP_V, the subexpression is certainly followed by OP_VERIFY.
806
1.66M
            if (node.fragment == Fragment::WRAP_V) return true;
807
            // The subexpression of WRAP_S, and the last subexpression of AND_V
808
            // inherit the followed-by-OP_VERIFY property from the parent.
809
1.65M
            if (node.fragment == Fragment::WRAP_S ||
810
1.65M
                (node.fragment == Fragment::AND_V && index == 1)) return verify;
811
1.65M
            return false;
812
1.65M
        };
813
        // The upward function computes for a node, given its followed-by-OP_VERIFY status
814
        // and the CScripts of its child nodes, the CScript of the node.
815
1.84k
        const bool is_tapscript{IsTapscript(m_script_ctx)};
816
1.68M
        auto upfn = [&ctx, is_tapscript](bool verify, const Node& node, std::span<CScript> subs) -> CScript {
817
1.68M
            switch (node.fragment) {
818
3.63k
                case Fragment::PK_K: return BuildScript(ctx.ToPKBytes(node.keys[0]));
819
590
                case Fragment::PK_H: return BuildScript(OP_DUP, OP_HASH160, ctx.ToPKHBytes(node.keys[0]), OP_EQUALVERIFY);
820
6.53k
                case Fragment::OLDER: return BuildScript(node.k, OP_CHECKSEQUENCEVERIFY);
821
1.13k
                case Fragment::AFTER: return BuildScript(node.k, OP_CHECKLOCKTIMEVERIFY);
822
133
                case Fragment::SHA256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_SHA256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
823
113
                case Fragment::RIPEMD160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_RIPEMD160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
824
162
                case Fragment::HASH256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
825
117
                case Fragment::HASH160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
826
7.82k
                case Fragment::WRAP_A: return BuildScript(OP_TOALTSTACK, subs[0], OP_FROMALTSTACK);
827
1.48k
                case Fragment::WRAP_S: return BuildScript(OP_SWAP, subs[0]);
828
4.16k
                case Fragment::WRAP_C: return BuildScript(std::move(subs[0]), verify ? OP_CHECKSIGVERIFY : OP_CHECKSIG);
829
145
                case Fragment::WRAP_D: return BuildScript(OP_DUP, OP_IF, subs[0], OP_ENDIF);
830
1.28k
                case Fragment::WRAP_V: {
831
1.28k
                    if (node.subs[0].GetType() << "x"_mst) {
832
352
                        return BuildScript(std::move(subs[0]), OP_VERIFY);
833
935
                    } else {
834
935
                        return std::move(subs[0]);
835
935
                    }
836
1.28k
                }
837
24
                case Fragment::WRAP_J: return BuildScript(OP_SIZE, OP_0NOTEQUAL, OP_IF, subs[0], OP_ENDIF);
838
1.64M
                case Fragment::WRAP_N: return BuildScript(std::move(subs[0]), OP_0NOTEQUAL);
839
236
                case Fragment::JUST_1: return BuildScript(OP_1);
840
1.14k
                case Fragment::JUST_0: return BuildScript(OP_0);
841
1.11k
                case Fragment::AND_V: return BuildScript(std::move(subs[0]), subs[1]);
842
7.42k
                case Fragment::AND_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLAND);
843
78
                case Fragment::OR_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLOR);
844
150
                case Fragment::OR_D: return BuildScript(std::move(subs[0]), OP_IFDUP, OP_NOTIF, subs[1], OP_ENDIF);
845
57
                case Fragment::OR_C: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[1], OP_ENDIF);
846
1.05k
                case Fragment::OR_I: return BuildScript(OP_IF, subs[0], OP_ELSE, subs[1], OP_ENDIF);
847
262
                case Fragment::ANDOR: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[2], OP_ELSE, subs[1], OP_ENDIF);
848
212
                case Fragment::MULTI: {
849
212
                    CHECK_NONFATAL(!is_tapscript);
850
212
                    CScript script = BuildScript(node.k);
851
445
                    for (const auto& key : node.keys) {
852
445
                        script = BuildScript(std::move(script), ctx.ToPKBytes(key));
853
445
                    }
854
212
                    return BuildScript(std::move(script), node.keys.size(), verify ? OP_CHECKMULTISIGVERIFY : OP_CHECKMULTISIG);
855
1.28k
                }
856
52
                case Fragment::MULTI_A: {
857
52
                    CHECK_NONFATAL(is_tapscript);
858
52
                    CScript script = BuildScript(ctx.ToPKBytes(*node.keys.begin()), OP_CHECKSIG);
859
197
                    for (auto it = node.keys.begin() + 1; it != node.keys.end(); ++it) {
860
145
                        script = BuildScript(std::move(script), ctx.ToPKBytes(*it), OP_CHECKSIGADD);
861
145
                    }
862
52
                    return BuildScript(std::move(script), node.k, verify ? OP_NUMEQUALVERIFY : OP_NUMEQUAL);
863
1.28k
                }
864
548
                case Fragment::THRESH: {
865
548
                    CScript script = std::move(subs[0]);
866
2.35k
                    for (size_t i = 1; i < subs.size(); ++i) {
867
1.80k
                        script = BuildScript(std::move(script), subs[i], OP_ADD);
868
1.80k
                    }
869
548
                    return BuildScript(std::move(script), node.k, verify ? OP_EQUALVERIFY : OP_EQUAL);
870
1.28k
                }
871
1.68M
            }
872
1.68M
            assert(false);
873
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
816
25.4k
        auto upfn = [&ctx, is_tapscript](bool verify, const Node& node, std::span<CScript> subs) -> CScript {
817
25.4k
            switch (node.fragment) {
818
1.36k
                case Fragment::PK_K: return BuildScript(ctx.ToPKBytes(node.keys[0]));
819
78
                case Fragment::PK_H: return BuildScript(OP_DUP, OP_HASH160, ctx.ToPKHBytes(node.keys[0]), OP_EQUALVERIFY);
820
6.11k
                case Fragment::OLDER: return BuildScript(node.k, OP_CHECKSEQUENCEVERIFY);
821
195
                case Fragment::AFTER: return BuildScript(node.k, OP_CHECKLOCKTIMEVERIFY);
822
63
                case Fragment::SHA256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_SHA256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
823
21
                case Fragment::RIPEMD160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_RIPEMD160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
824
42
                case Fragment::HASH256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
825
18
                case Fragment::HASH160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
826
7.33k
                case Fragment::WRAP_A: return BuildScript(OP_TOALTSTACK, subs[0], OP_FROMALTSTACK);
827
30
                case Fragment::WRAP_S: return BuildScript(OP_SWAP, subs[0]);
828
1.39k
                case Fragment::WRAP_C: return BuildScript(std::move(subs[0]), verify ? OP_CHECKSIGVERIFY : OP_CHECKSIG);
829
15
                case Fragment::WRAP_D: return BuildScript(OP_DUP, OP_IF, subs[0], OP_ENDIF);
830
243
                case Fragment::WRAP_V: {
831
243
                    if (node.subs[0].GetType() << "x"_mst) {
832
192
                        return BuildScript(std::move(subs[0]), OP_VERIFY);
833
192
                    } else {
834
51
                        return std::move(subs[0]);
835
51
                    }
836
243
                }
837
24
                case Fragment::WRAP_J: return BuildScript(OP_SIZE, OP_0NOTEQUAL, OP_IF, subs[0], OP_ENDIF);
838
45
                case Fragment::WRAP_N: return BuildScript(std::move(subs[0]), OP_0NOTEQUAL);
839
231
                case Fragment::JUST_1: return BuildScript(OP_1);
840
249
                case Fragment::JUST_0: return BuildScript(OP_0);
841
198
                case Fragment::AND_V: return BuildScript(std::move(subs[0]), subs[1]);
842
7.25k
                case Fragment::AND_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLAND);
843
24
                case Fragment::OR_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLOR);
844
45
                case Fragment::OR_D: return BuildScript(std::move(subs[0]), OP_IFDUP, OP_NOTIF, subs[1], OP_ENDIF);
845
18
                case Fragment::OR_C: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[1], OP_ENDIF);
846
237
                case Fragment::OR_I: return BuildScript(OP_IF, subs[0], OP_ELSE, subs[1], OP_ENDIF);
847
87
                case Fragment::ANDOR: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[2], OP_ELSE, subs[1], OP_ENDIF);
848
36
                case Fragment::MULTI: {
849
36
                    CHECK_NONFATAL(!is_tapscript);
850
36
                    CScript script = BuildScript(node.k);
851
69
                    for (const auto& key : node.keys) {
852
69
                        script = BuildScript(std::move(script), ctx.ToPKBytes(key));
853
69
                    }
854
36
                    return BuildScript(std::move(script), node.keys.size(), verify ? OP_CHECKMULTISIGVERIFY : OP_CHECKMULTISIG);
855
243
                }
856
6
                case Fragment::MULTI_A: {
857
6
                    CHECK_NONFATAL(is_tapscript);
858
6
                    CScript script = BuildScript(ctx.ToPKBytes(*node.keys.begin()), OP_CHECKSIG);
859
69
                    for (auto it = node.keys.begin() + 1; it != node.keys.end(); ++it) {
860
63
                        script = BuildScript(std::move(script), ctx.ToPKBytes(*it), OP_CHECKSIGADD);
861
63
                    }
862
6
                    return BuildScript(std::move(script), node.k, verify ? OP_NUMEQUALVERIFY : OP_NUMEQUAL);
863
243
                }
864
48
                case Fragment::THRESH: {
865
48
                    CScript script = std::move(subs[0]);
866
138
                    for (size_t i = 1; i < subs.size(); ++i) {
867
90
                        script = BuildScript(std::move(script), subs[i], OP_ADD);
868
90
                    }
869
48
                    return BuildScript(std::move(script), node.k, verify ? OP_EQUALVERIFY : OP_EQUAL);
870
243
                }
871
25.4k
            }
872
25.4k
            assert(false);
873
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
816
1.66M
        auto upfn = [&ctx, is_tapscript](bool verify, const Node& node, std::span<CScript> subs) -> CScript {
817
1.66M
            switch (node.fragment) {
818
2.26k
                case Fragment::PK_K: return BuildScript(ctx.ToPKBytes(node.keys[0]));
819
512
                case Fragment::PK_H: return BuildScript(OP_DUP, OP_HASH160, ctx.ToPKHBytes(node.keys[0]), OP_EQUALVERIFY);
820
424
                case Fragment::OLDER: return BuildScript(node.k, OP_CHECKSEQUENCEVERIFY);
821
935
                case Fragment::AFTER: return BuildScript(node.k, OP_CHECKLOCKTIMEVERIFY);
822
70
                case Fragment::SHA256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_SHA256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
823
92
                case Fragment::RIPEMD160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_RIPEMD160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
824
120
                case Fragment::HASH256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
825
99
                case Fragment::HASH160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
826
485
                case Fragment::WRAP_A: return BuildScript(OP_TOALTSTACK, subs[0], OP_FROMALTSTACK);
827
1.45k
                case Fragment::WRAP_S: return BuildScript(OP_SWAP, subs[0]);
828
2.77k
                case Fragment::WRAP_C: return BuildScript(std::move(subs[0]), verify ? OP_CHECKSIGVERIFY : OP_CHECKSIG);
829
130
                case Fragment::WRAP_D: return BuildScript(OP_DUP, OP_IF, subs[0], OP_ENDIF);
830
1.04k
                case Fragment::WRAP_V: {
831
1.04k
                    if (node.subs[0].GetType() << "x"_mst) {
832
160
                        return BuildScript(std::move(subs[0]), OP_VERIFY);
833
884
                    } else {
834
884
                        return std::move(subs[0]);
835
884
                    }
836
1.04k
                }
837
0
                case Fragment::WRAP_J: return BuildScript(OP_SIZE, OP_0NOTEQUAL, OP_IF, subs[0], OP_ENDIF);
838
1.64M
                case Fragment::WRAP_N: return BuildScript(std::move(subs[0]), OP_0NOTEQUAL);
839
5
                case Fragment::JUST_1: return BuildScript(OP_1);
840
893
                case Fragment::JUST_0: return BuildScript(OP_0);
841
914
                case Fragment::AND_V: return BuildScript(std::move(subs[0]), subs[1]);
842
172
                case Fragment::AND_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLAND);
843
54
                case Fragment::OR_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLOR);
844
105
                case Fragment::OR_D: return BuildScript(std::move(subs[0]), OP_IFDUP, OP_NOTIF, subs[1], OP_ENDIF);
845
39
                case Fragment::OR_C: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[1], OP_ENDIF);
846
816
                case Fragment::OR_I: return BuildScript(OP_IF, subs[0], OP_ELSE, subs[1], OP_ENDIF);
847
175
                case Fragment::ANDOR: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[2], OP_ELSE, subs[1], OP_ENDIF);
848
176
                case Fragment::MULTI: {
849
176
                    CHECK_NONFATAL(!is_tapscript);
850
176
                    CScript script = BuildScript(node.k);
851
376
                    for (const auto& key : node.keys) {
852
376
                        script = BuildScript(std::move(script), ctx.ToPKBytes(key));
853
376
                    }
854
176
                    return BuildScript(std::move(script), node.keys.size(), verify ? OP_CHECKMULTISIGVERIFY : OP_CHECKMULTISIG);
855
1.04k
                }
856
46
                case Fragment::MULTI_A: {
857
46
                    CHECK_NONFATAL(is_tapscript);
858
46
                    CScript script = BuildScript(ctx.ToPKBytes(*node.keys.begin()), OP_CHECKSIG);
859
128
                    for (auto it = node.keys.begin() + 1; it != node.keys.end(); ++it) {
860
82
                        script = BuildScript(std::move(script), ctx.ToPKBytes(*it), OP_CHECKSIGADD);
861
82
                    }
862
46
                    return BuildScript(std::move(script), node.k, verify ? OP_NUMEQUALVERIFY : OP_NUMEQUAL);
863
1.04k
                }
864
500
                case Fragment::THRESH: {
865
500
                    CScript script = std::move(subs[0]);
866
2.21k
                    for (size_t i = 1; i < subs.size(); ++i) {
867
1.71k
                        script = BuildScript(std::move(script), subs[i], OP_ADD);
868
1.71k
                    }
869
500
                    return BuildScript(std::move(script), node.k, verify ? OP_EQUALVERIFY : OP_EQUAL);
870
1.04k
                }
871
1.66M
            }
872
1.66M
            assert(false);
873
0
        };
874
1.84k
        return TreeEval<CScript>(false, downfn, upfn);
875
1.84k
    }
miniscript_tests.cpp:CScript miniscript::Node<CPubKey>::ToScript<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const
Line
Count
Source
800
375
    {
801
        // To construct the CScript for a Miniscript object, we use the TreeEval algorithm.
802
        // The State is a boolean: whether or not the node's script expansion is followed
803
        // by an OP_VERIFY (which may need to be combined with the last script opcode).
804
375
        auto downfn = [](bool verify, const Node& node, size_t index) {
805
            // For WRAP_V, the subexpression is certainly followed by OP_VERIFY.
806
375
            if (node.fragment == Fragment::WRAP_V) return true;
807
            // The subexpression of WRAP_S, and the last subexpression of AND_V
808
            // inherit the followed-by-OP_VERIFY property from the parent.
809
375
            if (node.fragment == Fragment::WRAP_S ||
810
375
                (node.fragment == Fragment::AND_V && index == 1)) return verify;
811
375
            return false;
812
375
        };
813
        // The upward function computes for a node, given its followed-by-OP_VERIFY status
814
        // and the CScripts of its child nodes, the CScript of the node.
815
375
        const bool is_tapscript{IsTapscript(m_script_ctx)};
816
375
        auto upfn = [&ctx, is_tapscript](bool verify, const Node& node, std::span<CScript> subs) -> CScript {
817
375
            switch (node.fragment) {
818
375
                case Fragment::PK_K: return BuildScript(ctx.ToPKBytes(node.keys[0]));
819
375
                case Fragment::PK_H: return BuildScript(OP_DUP, OP_HASH160, ctx.ToPKHBytes(node.keys[0]), OP_EQUALVERIFY);
820
375
                case Fragment::OLDER: return BuildScript(node.k, OP_CHECKSEQUENCEVERIFY);
821
375
                case Fragment::AFTER: return BuildScript(node.k, OP_CHECKLOCKTIMEVERIFY);
822
375
                case Fragment::SHA256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_SHA256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
823
375
                case Fragment::RIPEMD160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_RIPEMD160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
824
375
                case Fragment::HASH256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
825
375
                case Fragment::HASH160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
826
375
                case Fragment::WRAP_A: return BuildScript(OP_TOALTSTACK, subs[0], OP_FROMALTSTACK);
827
375
                case Fragment::WRAP_S: return BuildScript(OP_SWAP, subs[0]);
828
375
                case Fragment::WRAP_C: return BuildScript(std::move(subs[0]), verify ? OP_CHECKSIGVERIFY : OP_CHECKSIG);
829
375
                case Fragment::WRAP_D: return BuildScript(OP_DUP, OP_IF, subs[0], OP_ENDIF);
830
375
                case Fragment::WRAP_V: {
831
375
                    if (node.subs[0].GetType() << "x"_mst) {
832
375
                        return BuildScript(std::move(subs[0]), OP_VERIFY);
833
375
                    } else {
834
375
                        return std::move(subs[0]);
835
375
                    }
836
375
                }
837
375
                case Fragment::WRAP_J: return BuildScript(OP_SIZE, OP_0NOTEQUAL, OP_IF, subs[0], OP_ENDIF);
838
375
                case Fragment::WRAP_N: return BuildScript(std::move(subs[0]), OP_0NOTEQUAL);
839
375
                case Fragment::JUST_1: return BuildScript(OP_1);
840
375
                case Fragment::JUST_0: return BuildScript(OP_0);
841
375
                case Fragment::AND_V: return BuildScript(std::move(subs[0]), subs[1]);
842
375
                case Fragment::AND_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLAND);
843
375
                case Fragment::OR_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLOR);
844
375
                case Fragment::OR_D: return BuildScript(std::move(subs[0]), OP_IFDUP, OP_NOTIF, subs[1], OP_ENDIF);
845
375
                case Fragment::OR_C: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[1], OP_ENDIF);
846
375
                case Fragment::OR_I: return BuildScript(OP_IF, subs[0], OP_ELSE, subs[1], OP_ENDIF);
847
375
                case Fragment::ANDOR: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[2], OP_ELSE, subs[1], OP_ENDIF);
848
375
                case Fragment::MULTI: {
849
375
                    CHECK_NONFATAL(!is_tapscript);
850
375
                    CScript script = BuildScript(node.k);
851
375
                    for (const auto& key : node.keys) {
852
375
                        script = BuildScript(std::move(script), ctx.ToPKBytes(key));
853
375
                    }
854
375
                    return BuildScript(std::move(script), node.keys.size(), verify ? OP_CHECKMULTISIGVERIFY : OP_CHECKMULTISIG);
855
375
                }
856
375
                case Fragment::MULTI_A: {
857
375
                    CHECK_NONFATAL(is_tapscript);
858
375
                    CScript script = BuildScript(ctx.ToPKBytes(*node.keys.begin()), OP_CHECKSIG);
859
375
                    for (auto it = node.keys.begin() + 1; it != node.keys.end(); ++it) {
860
375
                        script = BuildScript(std::move(script), ctx.ToPKBytes(*it), OP_CHECKSIGADD);
861
375
                    }
862
375
                    return BuildScript(std::move(script), node.k, verify ? OP_NUMEQUALVERIFY : OP_NUMEQUAL);
863
375
                }
864
375
                case Fragment::THRESH: {
865
375
                    CScript script = std::move(subs[0]);
866
375
                    for (size_t i = 1; i < subs.size(); ++i) {
867
375
                        script = BuildScript(std::move(script), subs[i], OP_ADD);
868
375
                    }
869
375
                    return BuildScript(std::move(script), node.k, verify ? OP_EQUALVERIFY : OP_EQUAL);
870
375
                }
871
375
            }
872
375
            assert(false);
873
375
        };
874
375
        return TreeEval<CScript>(false, downfn, upfn);
875
375
    }
descriptor.cpp:CScript miniscript::Node<unsigned int>::ToScript<(anonymous namespace)::ScriptMaker>((anonymous namespace)::ScriptMaker const&) const
Line
Count
Source
800
1.47k
    {
801
        // To construct the CScript for a Miniscript object, we use the TreeEval algorithm.
802
        // The State is a boolean: whether or not the node's script expansion is followed
803
        // by an OP_VERIFY (which may need to be combined with the last script opcode).
804
1.47k
        auto downfn = [](bool verify, const Node& node, size_t index) {
805
            // For WRAP_V, the subexpression is certainly followed by OP_VERIFY.
806
1.47k
            if (node.fragment == Fragment::WRAP_V) return true;
807
            // The subexpression of WRAP_S, and the last subexpression of AND_V
808
            // inherit the followed-by-OP_VERIFY property from the parent.
809
1.47k
            if (node.fragment == Fragment::WRAP_S ||
810
1.47k
                (node.fragment == Fragment::AND_V && index == 1)) return verify;
811
1.47k
            return false;
812
1.47k
        };
813
        // The upward function computes for a node, given its followed-by-OP_VERIFY status
814
        // and the CScripts of its child nodes, the CScript of the node.
815
1.47k
        const bool is_tapscript{IsTapscript(m_script_ctx)};
816
1.47k
        auto upfn = [&ctx, is_tapscript](bool verify, const Node& node, std::span<CScript> subs) -> CScript {
817
1.47k
            switch (node.fragment) {
818
1.47k
                case Fragment::PK_K: return BuildScript(ctx.ToPKBytes(node.keys[0]));
819
1.47k
                case Fragment::PK_H: return BuildScript(OP_DUP, OP_HASH160, ctx.ToPKHBytes(node.keys[0]), OP_EQUALVERIFY);
820
1.47k
                case Fragment::OLDER: return BuildScript(node.k, OP_CHECKSEQUENCEVERIFY);
821
1.47k
                case Fragment::AFTER: return BuildScript(node.k, OP_CHECKLOCKTIMEVERIFY);
822
1.47k
                case Fragment::SHA256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_SHA256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
823
1.47k
                case Fragment::RIPEMD160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_RIPEMD160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
824
1.47k
                case Fragment::HASH256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
825
1.47k
                case Fragment::HASH160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
826
1.47k
                case Fragment::WRAP_A: return BuildScript(OP_TOALTSTACK, subs[0], OP_FROMALTSTACK);
827
1.47k
                case Fragment::WRAP_S: return BuildScript(OP_SWAP, subs[0]);
828
1.47k
                case Fragment::WRAP_C: return BuildScript(std::move(subs[0]), verify ? OP_CHECKSIGVERIFY : OP_CHECKSIG);
829
1.47k
                case Fragment::WRAP_D: return BuildScript(OP_DUP, OP_IF, subs[0], OP_ENDIF);
830
1.47k
                case Fragment::WRAP_V: {
831
1.47k
                    if (node.subs[0].GetType() << "x"_mst) {
832
1.47k
                        return BuildScript(std::move(subs[0]), OP_VERIFY);
833
1.47k
                    } else {
834
1.47k
                        return std::move(subs[0]);
835
1.47k
                    }
836
1.47k
                }
837
1.47k
                case Fragment::WRAP_J: return BuildScript(OP_SIZE, OP_0NOTEQUAL, OP_IF, subs[0], OP_ENDIF);
838
1.47k
                case Fragment::WRAP_N: return BuildScript(std::move(subs[0]), OP_0NOTEQUAL);
839
1.47k
                case Fragment::JUST_1: return BuildScript(OP_1);
840
1.47k
                case Fragment::JUST_0: return BuildScript(OP_0);
841
1.47k
                case Fragment::AND_V: return BuildScript(std::move(subs[0]), subs[1]);
842
1.47k
                case Fragment::AND_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLAND);
843
1.47k
                case Fragment::OR_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLOR);
844
1.47k
                case Fragment::OR_D: return BuildScript(std::move(subs[0]), OP_IFDUP, OP_NOTIF, subs[1], OP_ENDIF);
845
1.47k
                case Fragment::OR_C: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[1], OP_ENDIF);
846
1.47k
                case Fragment::OR_I: return BuildScript(OP_IF, subs[0], OP_ELSE, subs[1], OP_ENDIF);
847
1.47k
                case Fragment::ANDOR: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[2], OP_ELSE, subs[1], OP_ENDIF);
848
1.47k
                case Fragment::MULTI: {
849
1.47k
                    CHECK_NONFATAL(!is_tapscript);
850
1.47k
                    CScript script = BuildScript(node.k);
851
1.47k
                    for (const auto& key : node.keys) {
852
1.47k
                        script = BuildScript(std::move(script), ctx.ToPKBytes(key));
853
1.47k
                    }
854
1.47k
                    return BuildScript(std::move(script), node.keys.size(), verify ? OP_CHECKMULTISIGVERIFY : OP_CHECKMULTISIG);
855
1.47k
                }
856
1.47k
                case Fragment::MULTI_A: {
857
1.47k
                    CHECK_NONFATAL(is_tapscript);
858
1.47k
                    CScript script = BuildScript(ctx.ToPKBytes(*node.keys.begin()), OP_CHECKSIG);
859
1.47k
                    for (auto it = node.keys.begin() + 1; it != node.keys.end(); ++it) {
860
1.47k
                        script = BuildScript(std::move(script), ctx.ToPKBytes(*it), OP_CHECKSIGADD);
861
1.47k
                    }
862
1.47k
                    return BuildScript(std::move(script), node.k, verify ? OP_NUMEQUALVERIFY : OP_NUMEQUAL);
863
1.47k
                }
864
1.47k
                case Fragment::THRESH: {
865
1.47k
                    CScript script = std::move(subs[0]);
866
1.47k
                    for (size_t i = 1; i < subs.size(); ++i) {
867
1.47k
                        script = BuildScript(std::move(script), subs[i], OP_ADD);
868
1.47k
                    }
869
1.47k
                    return BuildScript(std::move(script), node.k, verify ? OP_EQUALVERIFY : OP_EQUAL);
870
1.47k
                }
871
1.47k
            }
872
1.47k
            assert(false);
873
1.47k
        };
874
1.47k
        return TreeEval<CScript>(false, downfn, upfn);
875
1.47k
    }
876
877
    template<typename CTx>
878
15
    std::optional<std::string> ToString(const CTx& ctx) const {
879
15
        bool dummy{false};
880
15
        return ToString(ctx, dummy);
881
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
878
1
    std::optional<std::string> ToString(const CTx& ctx) const {
879
1
        bool dummy{false};
880
1
        return ToString(ctx, dummy);
881
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
878
14
    std::optional<std::string> ToString(const CTx& ctx) const {
879
14
        bool dummy{false};
880
14
        return ToString(ctx, dummy);
881
14
    }
882
883
    template<typename CTx>
884
1.10k
    std::optional<std::string> ToString(const CTx& ctx, bool& has_priv_key) const {
885
        // To construct the std::string representation for a Miniscript object, we use
886
        // the TreeEvalMaybe algorithm. The State is a boolean: whether the parent node is a
887
        // wrapper. If so, non-wrapper expressions must be prefixed with a ":".
888
2.97M
        auto downfn = [](bool, const Node& node, size_t) {
889
2.97M
            return (node.fragment == Fragment::WRAP_A || node.fragment == Fragment::WRAP_S ||
890
2.97M
                    node.fragment == Fragment::WRAP_D || node.fragment == Fragment::WRAP_V ||
891
2.97M
                    node.fragment == Fragment::WRAP_J || node.fragment == Fragment::WRAP_N ||
892
2.97M
                    node.fragment == Fragment::WRAP_C ||
893
2.97M
                    (node.fragment == Fragment::AND_V && node.subs[1].fragment == Fragment::JUST_1) ||
894
2.97M
                    (node.fragment == Fragment::OR_I && node.subs[0].fragment == Fragment::JUST_0) ||
895
2.97M
                    (node.fragment == Fragment::OR_I && node.subs[1].fragment == Fragment::JUST_0));
896
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
888
3
        auto downfn = [](bool, const Node& node, size_t) {
889
3
            return (node.fragment == Fragment::WRAP_A || node.fragment == Fragment::WRAP_S ||
890
3
                    node.fragment == Fragment::WRAP_D || node.fragment == Fragment::WRAP_V ||
891
3
                    node.fragment == Fragment::WRAP_J || node.fragment == Fragment::WRAP_N ||
892
3
                    node.fragment == Fragment::WRAP_C ||
893
3
                    (node.fragment == Fragment::AND_V && node.subs[1].fragment == Fragment::JUST_1) ||
894
3
                    (node.fragment == Fragment::OR_I && node.subs[0].fragment == Fragment::JUST_0) ||
895
3
                    (node.fragment == Fragment::OR_I && node.subs[1].fragment == Fragment::JUST_0));
896
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
888
65
        auto downfn = [](bool, const Node& node, size_t) {
889
65
            return (node.fragment == Fragment::WRAP_A || node.fragment == Fragment::WRAP_S ||
890
65
                    node.fragment == Fragment::WRAP_D || node.fragment == Fragment::WRAP_V ||
891
65
                    node.fragment == Fragment::WRAP_J || node.fragment == Fragment::WRAP_N ||
892
65
                    node.fragment == Fragment::WRAP_C ||
893
65
                    (node.fragment == Fragment::AND_V && node.subs[1].fragment == Fragment::JUST_1) ||
894
65
                    (node.fragment == Fragment::OR_I && node.subs[0].fragment == Fragment::JUST_0) ||
895
65
                    (node.fragment == Fragment::OR_I && node.subs[1].fragment == Fragment::JUST_0));
896
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
888
2.97M
        auto downfn = [](bool, const Node& node, size_t) {
889
2.97M
            return (node.fragment == Fragment::WRAP_A || node.fragment == Fragment::WRAP_S ||
890
2.97M
                    node.fragment == Fragment::WRAP_D || node.fragment == Fragment::WRAP_V ||
891
2.97M
                    node.fragment == Fragment::WRAP_J || node.fragment == Fragment::WRAP_N ||
892
2.97M
                    node.fragment == Fragment::WRAP_C ||
893
2.97M
                    (node.fragment == Fragment::AND_V && node.subs[1].fragment == Fragment::JUST_1) ||
894
2.97M
                    (node.fragment == Fragment::OR_I && node.subs[0].fragment == Fragment::JUST_0) ||
895
2.97M
                    (node.fragment == Fragment::OR_I && node.subs[1].fragment == Fragment::JUST_0));
896
2.97M
        };
897
5.15k
        auto toString = [&ctx, &has_priv_key](Key key) -> std::optional<std::string> {
898
5.15k
            bool fragment_has_priv_key{false};
899
5.15k
            auto key_str{ctx.ToString(key, fragment_has_priv_key)};
900
5.15k
            if (key_str) has_priv_key = has_priv_key || fragment_has_priv_key;
901
5.15k
            return key_str;
902
5.15k
        };
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
897
30
        auto toString = [&ctx, &has_priv_key](Key key) -> std::optional<std::string> {
898
30
            bool fragment_has_priv_key{false};
899
30
            auto key_str{ctx.ToString(key, fragment_has_priv_key)};
900
30
            if (key_str) has_priv_key = has_priv_key || fragment_has_priv_key;
901
30
            return key_str;
902
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
897
5.12k
        auto toString = [&ctx, &has_priv_key](Key key) -> std::optional<std::string> {
898
5.12k
            bool fragment_has_priv_key{false};
899
5.12k
            auto key_str{ctx.ToString(key, fragment_has_priv_key)};
900
5.12k
            if (key_str) has_priv_key = has_priv_key || fragment_has_priv_key;
901
5.12k
            return key_str;
902
5.12k
        };
903
        // The upward function computes for a node, given whether its parent is a wrapper,
904
        // and the string representations of its child nodes, the string representation of the node.
905
1.10k
        const bool is_tapscript{IsTapscript(m_script_ctx)};
906
2.97M
        auto upfn = [is_tapscript, &toString](bool wrapped, const Node& node, std::span<std::string> subs) -> std::optional<std::string> {
907
2.97M
            std::string ret = wrapped ? ":" : "";
908
909
2.97M
            switch (node.fragment) {
910
609
                case Fragment::WRAP_A: return "a" + std::move(subs[0]);
911
338
                case Fragment::WRAP_S: return "s" + std::move(subs[0]);
912
2.38k
                case Fragment::WRAP_C:
913
2.38k
                    if (node.subs[0].fragment == Fragment::PK_K) {
914
                        // pk(K) is syntactic sugar for c:pk_k(K)
915
1.74k
                        auto key_str = toString(node.subs[0].keys[0]);
916
1.74k
                        if (!key_str) return {};
917
1.74k
                        return std::move(ret) + "pk(" + std::move(*key_str) + ")";
918
1.74k
                    }
919
647
                    if (node.subs[0].fragment == Fragment::PK_H) {
920
                        // pkh(K) is syntactic sugar for c:pk_h(K)
921
625
                        auto key_str = toString(node.subs[0].keys[0]);
922
625
                        if (!key_str) return {};
923
625
                        return std::move(ret) + "pkh(" + std::move(*key_str) + ")";
924
625
                    }
925
22
                    return "c" + std::move(subs[0]);
926
84
                case Fragment::WRAP_D: return "d" + std::move(subs[0]);
927
1.08k
                case Fragment::WRAP_V: return "v" + std::move(subs[0]);
928
0
                case Fragment::WRAP_J: return "j" + std::move(subs[0]);
929
2.96M
                case Fragment::WRAP_N: return "n" + std::move(subs[0]);
930
997
                case Fragment::AND_V:
931
                    // t:X is syntactic sugar for and_v(X,1).
932
997
                    if (node.subs[1].fragment == Fragment::JUST_1) return "t" + std::move(subs[0]);
933
991
                    break;
934
991
                case Fragment::OR_I:
935
229
                    if (node.subs[0].fragment == Fragment::JUST_0) return "l" + std::move(subs[1]);
936
108
                    if (node.subs[1].fragment == Fragment::JUST_0) return "u" + std::move(subs[0]);
937
108
                    break;
938
4.70k
                default: break;
939
2.97M
            }
940
5.80k
            switch (node.fragment) {
941
1.78k
                case Fragment::PK_K: {
942
1.78k
                    auto key_str = toString(node.keys[0]);
943
1.78k
                    if (!key_str) return {};
944
1.78k
                    return std::move(ret) + "pk_k(" + std::move(*key_str) + ")";
945
1.78k
                }
946
625
                case Fragment::PK_H: {
947
625
                    auto key_str = toString(node.keys[0]);
948
625
                    if (!key_str) return {};
949
625
                    return std::move(ret) + "pk_h(" + std::move(*key_str) + ")";
950
625
                }
951
436
                case Fragment::AFTER: return std::move(ret) + "after(" + util::ToString(node.k) + ")";
952
400
                case Fragment::OLDER: return std::move(ret) + "older(" + util::ToString(node.k) + ")";
953
30
                case Fragment::HASH256: return std::move(ret) + "hash256(" + HexStr(node.data) + ")";
954
63
                case Fragment::HASH160: return std::move(ret) + "hash160(" + HexStr(node.data) + ")";
955
71
                case Fragment::SHA256: return std::move(ret) + "sha256(" + HexStr(node.data) + ")";
956
35
                case Fragment::RIPEMD160: return std::move(ret) + "ripemd160(" + HexStr(node.data) + ")";
957
7
                case Fragment::JUST_1: return std::move(ret) + "1";
958
162
                case Fragment::JUST_0: return std::move(ret) + "0";
959
991
                case Fragment::AND_V: return std::move(ret) + "and_v(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
960
368
                case Fragment::AND_B: return std::move(ret) + "and_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
961
62
                case Fragment::OR_B: return std::move(ret) + "or_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
962
77
                case Fragment::OR_D: return std::move(ret) + "or_d(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
963
42
                case Fragment::OR_C: return std::move(ret) + "or_c(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
964
108
                case Fragment::OR_I: return std::move(ret) + "or_i(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
965
182
                case Fragment::ANDOR:
966
                    // and_n(X,Y) is syntactic sugar for andor(X,Y,0).
967
182
                    if (node.subs[2].fragment == Fragment::JUST_0) return std::move(ret) + "and_n(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
968
142
                    return std::move(ret) + "andor(" + std::move(subs[0]) + "," + std::move(subs[1]) + "," + std::move(subs[2]) + ")";
969
96
                case Fragment::MULTI: {
970
96
                    CHECK_NONFATAL(!is_tapscript);
971
96
                    auto str = std::move(ret) + "multi(" + util::ToString(node.k);
972
246
                    for (const auto& key : node.keys) {
973
246
                        auto key_str = toString(key);
974
246
                        if (!key_str) return {};
975
246
                        str += "," + std::move(*key_str);
976
246
                    }
977
96
                    return std::move(str) + ")";
978
96
                }
979
51
                case Fragment::MULTI_A: {
980
51
                    CHECK_NONFATAL(is_tapscript);
981
51
                    auto str = std::move(ret) + "multi_a(" + util::ToString(node.k);
982
130
                    for (const auto& key : node.keys) {
983
130
                        auto key_str = toString(key);
984
130
                        if (!key_str) return {};
985
130
                        str += "," + std::move(*key_str);
986
130
                    }
987
51
                    return std::move(str) + ")";
988
51
                }
989
211
                case Fragment::THRESH: {
990
211
                    auto str = std::move(ret) + "thresh(" + util::ToString(node.k);
991
730
                    for (auto& sub : subs) {
992
730
                        str += "," + std::move(sub);
993
730
                    }
994
211
                    return std::move(str) + ")";
995
51
                }
996
0
                default: break;
997
5.80k
            }
998
5.80k
            assert(false);
999
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
906
4
        auto upfn = [is_tapscript, &toString](bool wrapped, const Node& node, std::span<std::string> subs) -> std::optional<std::string> {
907
4
            std::string ret = wrapped ? ":" : "";
908
909
4
            switch (node.fragment) {
910
1
                case Fragment::WRAP_A: return "a" + std::move(subs[0]);
911
0
                case Fragment::WRAP_S: return "s" + std::move(subs[0]);
912
0
                case Fragment::WRAP_C:
913
0
                    if (node.subs[0].fragment == Fragment::PK_K) {
914
                        // pk(K) is syntactic sugar for c:pk_k(K)
915
0
                        auto key_str = toString(node.subs[0].keys[0]);
916
0
                        if (!key_str) return {};
917
0
                        return std::move(ret) + "pk(" + std::move(*key_str) + ")";
918
0
                    }
919
0
                    if (node.subs[0].fragment == Fragment::PK_H) {
920
                        // pkh(K) is syntactic sugar for c:pk_h(K)
921
0
                        auto key_str = toString(node.subs[0].keys[0]);
922
0
                        if (!key_str) return {};
923
0
                        return std::move(ret) + "pkh(" + std::move(*key_str) + ")";
924
0
                    }
925
0
                    return "c" + std::move(subs[0]);
926
0
                case Fragment::WRAP_D: return "d" + std::move(subs[0]);
927
0
                case Fragment::WRAP_V: return "v" + std::move(subs[0]);
928
0
                case Fragment::WRAP_J: return "j" + std::move(subs[0]);
929
0
                case Fragment::WRAP_N: return "n" + std::move(subs[0]);
930
0
                case Fragment::AND_V:
931
                    // t:X is syntactic sugar for and_v(X,1).
932
0
                    if (node.subs[1].fragment == Fragment::JUST_1) return "t" + std::move(subs[0]);
933
0
                    break;
934
0
                case Fragment::OR_I:
935
0
                    if (node.subs[0].fragment == Fragment::JUST_0) return "l" + std::move(subs[1]);
936
0
                    if (node.subs[1].fragment == Fragment::JUST_0) return "u" + std::move(subs[0]);
937
0
                    break;
938
3
                default: break;
939
4
            }
940
3
            switch (node.fragment) {
941
0
                case Fragment::PK_K: {
942
0
                    auto key_str = toString(node.keys[0]);
943
0
                    if (!key_str) return {};
944
0
                    return std::move(ret) + "pk_k(" + std::move(*key_str) + ")";
945
0
                }
946
0
                case Fragment::PK_H: {
947
0
                    auto key_str = toString(node.keys[0]);
948
0
                    if (!key_str) return {};
949
0
                    return std::move(ret) + "pk_h(" + std::move(*key_str) + ")";
950
0
                }
951
2
                case Fragment::AFTER: return std::move(ret) + "after(" + util::ToString(node.k) + ")";
952
0
                case Fragment::OLDER: return std::move(ret) + "older(" + util::ToString(node.k) + ")";
953
0
                case Fragment::HASH256: return std::move(ret) + "hash256(" + HexStr(node.data) + ")";
954
0
                case Fragment::HASH160: return std::move(ret) + "hash160(" + HexStr(node.data) + ")";
955
0
                case Fragment::SHA256: return std::move(ret) + "sha256(" + HexStr(node.data) + ")";
956
0
                case Fragment::RIPEMD160: return std::move(ret) + "ripemd160(" + HexStr(node.data) + ")";
957
0
                case Fragment::JUST_1: return std::move(ret) + "1";
958
0
                case Fragment::JUST_0: return std::move(ret) + "0";
959
0
                case Fragment::AND_V: return std::move(ret) + "and_v(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
960
1
                case Fragment::AND_B: return std::move(ret) + "and_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
961
0
                case Fragment::OR_B: return std::move(ret) + "or_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
962
0
                case Fragment::OR_D: return std::move(ret) + "or_d(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
963
0
                case Fragment::OR_C: return std::move(ret) + "or_c(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
964
0
                case Fragment::OR_I: return std::move(ret) + "or_i(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
965
0
                case Fragment::ANDOR:
966
                    // and_n(X,Y) is syntactic sugar for andor(X,Y,0).
967
0
                    if (node.subs[2].fragment == Fragment::JUST_0) return std::move(ret) + "and_n(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
968
0
                    return std::move(ret) + "andor(" + std::move(subs[0]) + "," + std::move(subs[1]) + "," + std::move(subs[2]) + ")";
969
0
                case Fragment::MULTI: {
970
0
                    CHECK_NONFATAL(!is_tapscript);
971
0
                    auto str = std::move(ret) + "multi(" + util::ToString(node.k);
972
0
                    for (const auto& key : node.keys) {
973
0
                        auto key_str = toString(key);
974
0
                        if (!key_str) return {};
975
0
                        str += "," + std::move(*key_str);
976
0
                    }
977
0
                    return std::move(str) + ")";
978
0
                }
979
0
                case Fragment::MULTI_A: {
980
0
                    CHECK_NONFATAL(is_tapscript);
981
0
                    auto str = std::move(ret) + "multi_a(" + util::ToString(node.k);
982
0
                    for (const auto& key : node.keys) {
983
0
                        auto key_str = toString(key);
984
0
                        if (!key_str) return {};
985
0
                        str += "," + std::move(*key_str);
986
0
                    }
987
0
                    return std::move(str) + ")";
988
0
                }
989
0
                case Fragment::THRESH: {
990
0
                    auto str = std::move(ret) + "thresh(" + util::ToString(node.k);
991
0
                    for (auto& sub : subs) {
992
0
                        str += "," + std::move(sub);
993
0
                    }
994
0
                    return std::move(str) + ")";
995
0
                }
996
0
                default: break;
997
3
            }
998
3
            assert(false);
999
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
906
79
        auto upfn = [is_tapscript, &toString](bool wrapped, const Node& node, std::span<std::string> subs) -> std::optional<std::string> {
907
79
            std::string ret = wrapped ? ":" : "";
908
909
79
            switch (node.fragment) {
910
3
                case Fragment::WRAP_A: return "a" + std::move(subs[0]);
911
6
                case Fragment::WRAP_S: return "s" + std::move(subs[0]);
912
14
                case Fragment::WRAP_C:
913
14
                    if (node.subs[0].fragment == Fragment::PK_K) {
914
                        // pk(K) is syntactic sugar for c:pk_k(K)
915
10
                        auto key_str = toString(node.subs[0].keys[0]);
916
10
                        if (!key_str) return {};
917
10
                        return std::move(ret) + "pk(" + std::move(*key_str) + ")";
918
10
                    }
919
4
                    if (node.subs[0].fragment == Fragment::PK_H) {
920
                        // pkh(K) is syntactic sugar for c:pk_h(K)
921
2
                        auto key_str = toString(node.subs[0].keys[0]);
922
2
                        if (!key_str) return {};
923
2
                        return std::move(ret) + "pkh(" + std::move(*key_str) + ")";
924
2
                    }
925
2
                    return "c" + std::move(subs[0]);
926
0
                case Fragment::WRAP_D: return "d" + std::move(subs[0]);
927
6
                case Fragment::WRAP_V: return "v" + std::move(subs[0]);
928
0
                case Fragment::WRAP_J: return "j" + std::move(subs[0]);
929
0
                case Fragment::WRAP_N: return "n" + std::move(subs[0]);
930
2
                case Fragment::AND_V:
931
                    // t:X is syntactic sugar for and_v(X,1).
932
2
                    if (node.subs[1].fragment == Fragment::JUST_1) return "t" + std::move(subs[0]);
933
2
                    break;
934
2
                case Fragment::OR_I:
935
2
                    if (node.subs[0].fragment == Fragment::JUST_0) return "l" + std::move(subs[1]);
936
2
                    if (node.subs[1].fragment == Fragment::JUST_0) return "u" + std::move(subs[0]);
937
2
                    break;
938
46
                default: break;
939
79
            }
940
50
            switch (node.fragment) {
941
16
                case Fragment::PK_K: {
942
16
                    auto key_str = toString(node.keys[0]);
943
16
                    if (!key_str) return {};
944
16
                    return std::move(ret) + "pk_k(" + std::move(*key_str) + ")";
945
16
                }
946
2
                case Fragment::PK_H: {
947
2
                    auto key_str = toString(node.keys[0]);
948
2
                    if (!key_str) return {};
949
2
                    return std::move(ret) + "pk_h(" + std::move(*key_str) + ")";
950
2
                }
951
2
                case Fragment::AFTER: return std::move(ret) + "after(" + util::ToString(node.k) + ")";
952
8
                case Fragment::OLDER: return std::move(ret) + "older(" + util::ToString(node.k) + ")";
953
0
                case Fragment::HASH256: return std::move(ret) + "hash256(" + HexStr(node.data) + ")";
954
0
                case Fragment::HASH160: return std::move(ret) + "hash160(" + HexStr(node.data) + ")";
955
2
                case Fragment::SHA256: return std::move(ret) + "sha256(" + HexStr(node.data) + ")";
956
1
                case Fragment::RIPEMD160: return std::move(ret) + "ripemd160(" + HexStr(node.data) + ")";
957
1
                case Fragment::JUST_1: return std::move(ret) + "1";
958
1
                case Fragment::JUST_0: return std::move(ret) + "0";
959
2
                case Fragment::AND_V: return std::move(ret) + "and_v(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
960
7
                case Fragment::AND_B: return std::move(ret) + "and_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
961
4
                case Fragment::OR_B: return std::move(ret) + "or_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
962
0
                case Fragment::OR_D: return std::move(ret) + "or_d(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
963
0
                case Fragment::OR_C: return std::move(ret) + "or_c(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
964
2
                case Fragment::OR_I: return std::move(ret) + "or_i(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
965
2
                case Fragment::ANDOR:
966
                    // and_n(X,Y) is syntactic sugar for andor(X,Y,0).
967
2
                    if (node.subs[2].fragment == Fragment::JUST_0) return std::move(ret) + "and_n(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
968
2
                    return std::move(ret) + "andor(" + std::move(subs[0]) + "," + std::move(subs[1]) + "," + std::move(subs[2]) + ")";
969
0
                case Fragment::MULTI: {
970
0
                    CHECK_NONFATAL(!is_tapscript);
971
0
                    auto str = std::move(ret) + "multi(" + util::ToString(node.k);
972
0
                    for (const auto& key : node.keys) {
973
0
                        auto key_str = toString(key);
974
0
                        if (!key_str) return {};
975
0
                        str += "," + std::move(*key_str);
976
0
                    }
977
0
                    return std::move(str) + ")";
978
0
                }
979
0
                case Fragment::MULTI_A: {
980
0
                    CHECK_NONFATAL(is_tapscript);
981
0
                    auto str = std::move(ret) + "multi_a(" + util::ToString(node.k);
982
0
                    for (const auto& key : node.keys) {
983
0
                        auto key_str = toString(key);
984
0
                        if (!key_str) return {};
985
0
                        str += "," + std::move(*key_str);
986
0
                    }
987
0
                    return std::move(str) + ")";
988
0
                }
989
0
                case Fragment::THRESH: {
990
0
                    auto str = std::move(ret) + "thresh(" + util::ToString(node.k);
991
0
                    for (auto& sub : subs) {
992
0
                        str += "," + std::move(sub);
993
0
                    }
994
0
                    return std::move(str) + ")";
995
0
                }
996
0
                default: break;
997
50
            }
998
50
            assert(false);
999
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
906
2.97M
        auto upfn = [is_tapscript, &toString](bool wrapped, const Node& node, std::span<std::string> subs) -> std::optional<std::string> {
907
2.97M
            std::string ret = wrapped ? ":" : "";
908
909
2.97M
            switch (node.fragment) {
910
605
                case Fragment::WRAP_A: return "a" + std::move(subs[0]);
911
332
                case Fragment::WRAP_S: return "s" + std::move(subs[0]);
912
2.37k
                case Fragment::WRAP_C:
913
2.37k
                    if (node.subs[0].fragment == Fragment::PK_K) {
914
                        // pk(K) is syntactic sugar for c:pk_k(K)
915
1.73k
                        auto key_str = toString(node.subs[0].keys[0]);
916
1.73k
                        if (!key_str) return {};
917
1.73k
                        return std::move(ret) + "pk(" + std::move(*key_str) + ")";
918
1.73k
                    }
919
643
                    if (node.subs[0].fragment == Fragment::PK_H) {
920
                        // pkh(K) is syntactic sugar for c:pk_h(K)
921
623
                        auto key_str = toString(node.subs[0].keys[0]);
922
623
                        if (!key_str) return {};
923
623
                        return std::move(ret) + "pkh(" + std::move(*key_str) + ")";
924
623
                    }
925
20
                    return "c" + std::move(subs[0]);
926
84
                case Fragment::WRAP_D: return "d" + std::move(subs[0]);
927
1.07k
                case Fragment::WRAP_V: return "v" + std::move(subs[0]);
928
0
                case Fragment::WRAP_J: return "j" + std::move(subs[0]);
929
2.96M
                case Fragment::WRAP_N: return "n" + std::move(subs[0]);
930
995
                case Fragment::AND_V:
931
                    // t:X is syntactic sugar for and_v(X,1).
932
995
                    if (node.subs[1].fragment == Fragment::JUST_1) return "t" + std::move(subs[0]);
933
989
                    break;
934
989
                case Fragment::OR_I:
935
227
                    if (node.subs[0].fragment == Fragment::JUST_0) return "l" + std::move(subs[1]);
936
106
                    if (node.subs[1].fragment == Fragment::JUST_0) return "u" + std::move(subs[0]);
937
106
                    break;
938
4.65k
                default: break;
939
2.97M
            }
940
5.75k
            switch (node.fragment) {
941
1.77k
                case Fragment::PK_K: {
942
1.77k
                    auto key_str = toString(node.keys[0]);
943
1.77k
                    if (!key_str) return {};
944
1.77k
                    return std::move(ret) + "pk_k(" + std::move(*key_str) + ")";
945
1.77k
                }
946
623
                case Fragment::PK_H: {
947
623
                    auto key_str = toString(node.keys[0]);
948
623
                    if (!key_str) return {};
949
623
                    return std::move(ret) + "pk_h(" + std::move(*key_str) + ")";
950
623
                }
951
432
                case Fragment::AFTER: return std::move(ret) + "after(" + util::ToString(node.k) + ")";
952
392
                case Fragment::OLDER: return std::move(ret) + "older(" + util::ToString(node.k) + ")";
953
30
                case Fragment::HASH256: return std::move(ret) + "hash256(" + HexStr(node.data) + ")";
954
63
                case Fragment::HASH160: return std::move(ret) + "hash160(" + HexStr(node.data) + ")";
955
69
                case Fragment::SHA256: return std::move(ret) + "sha256(" + HexStr(node.data) + ")";
956
34
                case Fragment::RIPEMD160: return std::move(ret) + "ripemd160(" + HexStr(node.data) + ")";
957
6
                case Fragment::JUST_1: return std::move(ret) + "1";
958
161
                case Fragment::JUST_0: return std::move(ret) + "0";
959
989
                case Fragment::AND_V: return std::move(ret) + "and_v(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
960
360
                case Fragment::AND_B: return std::move(ret) + "and_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
961
58
                case Fragment::OR_B: return std::move(ret) + "or_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
962
77
                case Fragment::OR_D: return std::move(ret) + "or_d(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
963
42
                case Fragment::OR_C: return std::move(ret) + "or_c(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
964
106
                case Fragment::OR_I: return std::move(ret) + "or_i(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
965
180
                case Fragment::ANDOR:
966
                    // and_n(X,Y) is syntactic sugar for andor(X,Y,0).
967
180
                    if (node.subs[2].fragment == Fragment::JUST_0) return std::move(ret) + "and_n(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
968
140
                    return std::move(ret) + "andor(" + std::move(subs[0]) + "," + std::move(subs[1]) + "," + std::move(subs[2]) + ")";
969
96
                case Fragment::MULTI: {
970
96
                    CHECK_NONFATAL(!is_tapscript);
971
96
                    auto str = std::move(ret) + "multi(" + util::ToString(node.k);
972
246
                    for (const auto& key : node.keys) {
973
246
                        auto key_str = toString(key);
974
246
                        if (!key_str) return {};
975
246
                        str += "," + std::move(*key_str);
976
246
                    }
977
96
                    return std::move(str) + ")";
978
96
                }
979
51
                case Fragment::MULTI_A: {
980
51
                    CHECK_NONFATAL(is_tapscript);
981
51
                    auto str = std::move(ret) + "multi_a(" + util::ToString(node.k);
982
130
                    for (const auto& key : node.keys) {
983
130
                        auto key_str = toString(key);
984
130
                        if (!key_str) return {};
985
130
                        str += "," + std::move(*key_str);
986
130
                    }
987
51
                    return std::move(str) + ")";
988
51
                }
989
211
                case Fragment::THRESH: {
990
211
                    auto str = std::move(ret) + "thresh(" + util::ToString(node.k);
991
730
                    for (auto& sub : subs) {
992
730
                        str += "," + std::move(sub);
993
730
                    }
994
211
                    return std::move(str) + ")";
995
51
                }
996
0
                default: break;
997
5.75k
            }
998
5.75k
            assert(false);
999
0
        };
1000
1001
1.10k
        return TreeEvalMaybe<std::string>(false, downfn, upfn);
1002
1.10k
    }
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
884
1
    std::optional<std::string> ToString(const CTx& ctx, bool& has_priv_key) const {
885
        // To construct the std::string representation for a Miniscript object, we use
886
        // the TreeEvalMaybe algorithm. The State is a boolean: whether the parent node is a
887
        // wrapper. If so, non-wrapper expressions must be prefixed with a ":".
888
1
        auto downfn = [](bool, const Node& node, size_t) {
889
1
            return (node.fragment == Fragment::WRAP_A || node.fragment == Fragment::WRAP_S ||
890
1
                    node.fragment == Fragment::WRAP_D || node.fragment == Fragment::WRAP_V ||
891
1
                    node.fragment == Fragment::WRAP_J || node.fragment == Fragment::WRAP_N ||
892
1
                    node.fragment == Fragment::WRAP_C ||
893
1
                    (node.fragment == Fragment::AND_V && node.subs[1].fragment == Fragment::JUST_1) ||
894
1
                    (node.fragment == Fragment::OR_I && node.subs[0].fragment == Fragment::JUST_0) ||
895
1
                    (node.fragment == Fragment::OR_I && node.subs[1].fragment == Fragment::JUST_0));
896
1
        };
897
1
        auto toString = [&ctx, &has_priv_key](Key key) -> std::optional<std::string> {
898
1
            bool fragment_has_priv_key{false};
899
1
            auto key_str{ctx.ToString(key, fragment_has_priv_key)};
900
1
            if (key_str) has_priv_key = has_priv_key || fragment_has_priv_key;
901
1
            return key_str;
902
1
        };
903
        // The upward function computes for a node, given whether its parent is a wrapper,
904
        // and the string representations of its child nodes, the string representation of the node.
905
1
        const bool is_tapscript{IsTapscript(m_script_ctx)};
906
1
        auto upfn = [is_tapscript, &toString](bool wrapped, const Node& node, std::span<std::string> subs) -> std::optional<std::string> {
907
1
            std::string ret = wrapped ? ":" : "";
908
909
1
            switch (node.fragment) {
910
1
                case Fragment::WRAP_A: return "a" + std::move(subs[0]);
911
1
                case Fragment::WRAP_S: return "s" + std::move(subs[0]);
912
1
                case Fragment::WRAP_C:
913
1
                    if (node.subs[0].fragment == Fragment::PK_K) {
914
                        // pk(K) is syntactic sugar for c:pk_k(K)
915
1
                        auto key_str = toString(node.subs[0].keys[0]);
916
1
                        if (!key_str) return {};
917
1
                        return std::move(ret) + "pk(" + std::move(*key_str) + ")";
918
1
                    }
919
1
                    if (node.subs[0].fragment == Fragment::PK_H) {
920
                        // pkh(K) is syntactic sugar for c:pk_h(K)
921
1
                        auto key_str = toString(node.subs[0].keys[0]);
922
1
                        if (!key_str) return {};
923
1
                        return std::move(ret) + "pkh(" + std::move(*key_str) + ")";
924
1
                    }
925
1
                    return "c" + std::move(subs[0]);
926
1
                case Fragment::WRAP_D: return "d" + std::move(subs[0]);
927
1
                case Fragment::WRAP_V: return "v" + std::move(subs[0]);
928
1
                case Fragment::WRAP_J: return "j" + std::move(subs[0]);
929
1
                case Fragment::WRAP_N: return "n" + std::move(subs[0]);
930
1
                case Fragment::AND_V:
931
                    // t:X is syntactic sugar for and_v(X,1).
932
1
                    if (node.subs[1].fragment == Fragment::JUST_1) return "t" + std::move(subs[0]);
933
1
                    break;
934
1
                case Fragment::OR_I:
935
1
                    if (node.subs[0].fragment == Fragment::JUST_0) return "l" + std::move(subs[1]);
936
1
                    if (node.subs[1].fragment == Fragment::JUST_0) return "u" + std::move(subs[0]);
937
1
                    break;
938
1
                default: break;
939
1
            }
940
1
            switch (node.fragment) {
941
1
                case Fragment::PK_K: {
942
1
                    auto key_str = toString(node.keys[0]);
943
1
                    if (!key_str) return {};
944
1
                    return std::move(ret) + "pk_k(" + std::move(*key_str) + ")";
945
1
                }
946
1
                case Fragment::PK_H: {
947
1
                    auto key_str = toString(node.keys[0]);
948
1
                    if (!key_str) return {};
949
1
                    return std::move(ret) + "pk_h(" + std::move(*key_str) + ")";
950
1
                }
951
1
                case Fragment::AFTER: return std::move(ret) + "after(" + util::ToString(node.k) + ")";
952
1
                case Fragment::OLDER: return std::move(ret) + "older(" + util::ToString(node.k) + ")";
953
1
                case Fragment::HASH256: return std::move(ret) + "hash256(" + HexStr(node.data) + ")";
954
1
                case Fragment::HASH160: return std::move(ret) + "hash160(" + HexStr(node.data) + ")";
955
1
                case Fragment::SHA256: return std::move(ret) + "sha256(" + HexStr(node.data) + ")";
956
1
                case Fragment::RIPEMD160: return std::move(ret) + "ripemd160(" + HexStr(node.data) + ")";
957
1
                case Fragment::JUST_1: return std::move(ret) + "1";
958
1
                case Fragment::JUST_0: return std::move(ret) + "0";
959
1
                case Fragment::AND_V: return std::move(ret) + "and_v(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
960
1
                case Fragment::AND_B: return std::move(ret) + "and_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
961
1
                case Fragment::OR_B: return std::move(ret) + "or_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
962
1
                case Fragment::OR_D: return std::move(ret) + "or_d(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
963
1
                case Fragment::OR_C: return std::move(ret) + "or_c(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
964
1
                case Fragment::OR_I: return std::move(ret) + "or_i(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
965
1
                case Fragment::ANDOR:
966
                    // and_n(X,Y) is syntactic sugar for andor(X,Y,0).
967
1
                    if (node.subs[2].fragment == Fragment::JUST_0) return std::move(ret) + "and_n(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
968
1
                    return std::move(ret) + "andor(" + std::move(subs[0]) + "," + std::move(subs[1]) + "," + std::move(subs[2]) + ")";
969
1
                case Fragment::MULTI: {
970
1
                    CHECK_NONFATAL(!is_tapscript);
971
1
                    auto str = std::move(ret) + "multi(" + util::ToString(node.k);
972
1
                    for (const auto& key : node.keys) {
973
1
                        auto key_str = toString(key);
974
1
                        if (!key_str) return {};
975
1
                        str += "," + std::move(*key_str);
976
1
                    }
977
1
                    return std::move(str) + ")";
978
1
                }
979
1
                case Fragment::MULTI_A: {
980
1
                    CHECK_NONFATAL(is_tapscript);
981
1
                    auto str = std::move(ret) + "multi_a(" + util::ToString(node.k);
982
1
                    for (const auto& key : node.keys) {
983
1
                        auto key_str = toString(key);
984
1
                        if (!key_str) return {};
985
1
                        str += "," + std::move(*key_str);
986
1
                    }
987
1
                    return std::move(str) + ")";
988
1
                }
989
1
                case Fragment::THRESH: {
990
1
                    auto str = std::move(ret) + "thresh(" + util::ToString(node.k);
991
1
                    for (auto& sub : subs) {
992
1
                        str += "," + std::move(sub);
993
1
                    }
994
1
                    return std::move(str) + ")";
995
1
                }
996
1
                default: break;
997
1
            }
998
1
            assert(false);
999
1
        };
1000
1001
1
        return TreeEvalMaybe<std::string>(false, downfn, upfn);
1002
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
884
14
    std::optional<std::string> ToString(const CTx& ctx, bool& has_priv_key) const {
885
        // To construct the std::string representation for a Miniscript object, we use
886
        // the TreeEvalMaybe algorithm. The State is a boolean: whether the parent node is a
887
        // wrapper. If so, non-wrapper expressions must be prefixed with a ":".
888
14
        auto downfn = [](bool, const Node& node, size_t) {
889
14
            return (node.fragment == Fragment::WRAP_A || node.fragment == Fragment::WRAP_S ||
890
14
                    node.fragment == Fragment::WRAP_D || node.fragment == Fragment::WRAP_V ||
891
14
                    node.fragment == Fragment::WRAP_J || node.fragment == Fragment::WRAP_N ||
892
14
                    node.fragment == Fragment::WRAP_C ||
893
14
                    (node.fragment == Fragment::AND_V && node.subs[1].fragment == Fragment::JUST_1) ||
894
14
                    (node.fragment == Fragment::OR_I && node.subs[0].fragment == Fragment::JUST_0) ||
895
14
                    (node.fragment == Fragment::OR_I && node.subs[1].fragment == Fragment::JUST_0));
896
14
        };
897
14
        auto toString = [&ctx, &has_priv_key](Key key) -> std::optional<std::string> {
898
14
            bool fragment_has_priv_key{false};
899
14
            auto key_str{ctx.ToString(key, fragment_has_priv_key)};
900
14
            if (key_str) has_priv_key = has_priv_key || fragment_has_priv_key;
901
14
            return key_str;
902
14
        };
903
        // The upward function computes for a node, given whether its parent is a wrapper,
904
        // and the string representations of its child nodes, the string representation of the node.
905
14
        const bool is_tapscript{IsTapscript(m_script_ctx)};
906
14
        auto upfn = [is_tapscript, &toString](bool wrapped, const Node& node, std::span<std::string> subs) -> std::optional<std::string> {
907
14
            std::string ret = wrapped ? ":" : "";
908
909
14
            switch (node.fragment) {
910
14
                case Fragment::WRAP_A: return "a" + std::move(subs[0]);
911
14
                case Fragment::WRAP_S: return "s" + std::move(subs[0]);
912
14
                case Fragment::WRAP_C:
913
14
                    if (node.subs[0].fragment == Fragment::PK_K) {
914
                        // pk(K) is syntactic sugar for c:pk_k(K)
915
14
                        auto key_str = toString(node.subs[0].keys[0]);
916
14
                        if (!key_str) return {};
917
14
                        return std::move(ret) + "pk(" + std::move(*key_str) + ")";
918
14
                    }
919
14
                    if (node.subs[0].fragment == Fragment::PK_H) {
920
                        // pkh(K) is syntactic sugar for c:pk_h(K)
921
14
                        auto key_str = toString(node.subs[0].keys[0]);
922
14
                        if (!key_str) return {};
923
14
                        return std::move(ret) + "pkh(" + std::move(*key_str) + ")";
924
14
                    }
925
14
                    return "c" + std::move(subs[0]);
926
14
                case Fragment::WRAP_D: return "d" + std::move(subs[0]);
927
14
                case Fragment::WRAP_V: return "v" + std::move(subs[0]);
928
14
                case Fragment::WRAP_J: return "j" + std::move(subs[0]);
929
14
                case Fragment::WRAP_N: return "n" + std::move(subs[0]);
930
14
                case Fragment::AND_V:
931
                    // t:X is syntactic sugar for and_v(X,1).
932
14
                    if (node.subs[1].fragment == Fragment::JUST_1) return "t" + std::move(subs[0]);
933
14
                    break;
934
14
                case Fragment::OR_I:
935
14
                    if (node.subs[0].fragment == Fragment::JUST_0) return "l" + std::move(subs[1]);
936
14
                    if (node.subs[1].fragment == Fragment::JUST_0) return "u" + std::move(subs[0]);
937
14
                    break;
938
14
                default: break;
939
14
            }
940
14
            switch (node.fragment) {
941
14
                case Fragment::PK_K: {
942
14
                    auto key_str = toString(node.keys[0]);
943
14
                    if (!key_str) return {};
944
14
                    return std::move(ret) + "pk_k(" + std::move(*key_str) + ")";
945
14
                }
946
14
                case Fragment::PK_H: {
947
14
                    auto key_str = toString(node.keys[0]);
948
14
                    if (!key_str) return {};
949
14
                    return std::move(ret) + "pk_h(" + std::move(*key_str) + ")";
950
14
                }
951
14
                case Fragment::AFTER: return std::move(ret) + "after(" + util::ToString(node.k) + ")";
952
14
                case Fragment::OLDER: return std::move(ret) + "older(" + util::ToString(node.k) + ")";
953
14
                case Fragment::HASH256: return std::move(ret) + "hash256(" + HexStr(node.data) + ")";
954
14
                case Fragment::HASH160: return std::move(ret) + "hash160(" + HexStr(node.data) + ")";
955
14
                case Fragment::SHA256: return std::move(ret) + "sha256(" + HexStr(node.data) + ")";
956
14
                case Fragment::RIPEMD160: return std::move(ret) + "ripemd160(" + HexStr(node.data) + ")";
957
14
                case Fragment::JUST_1: return std::move(ret) + "1";
958
14
                case Fragment::JUST_0: return std::move(ret) + "0";
959
14
                case Fragment::AND_V: return std::move(ret) + "and_v(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
960
14
                case Fragment::AND_B: return std::move(ret) + "and_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
961
14
                case Fragment::OR_B: return std::move(ret) + "or_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
962
14
                case Fragment::OR_D: return std::move(ret) + "or_d(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
963
14
                case Fragment::OR_C: return std::move(ret) + "or_c(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
964
14
                case Fragment::OR_I: return std::move(ret) + "or_i(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
965
14
                case Fragment::ANDOR:
966
                    // and_n(X,Y) is syntactic sugar for andor(X,Y,0).
967
14
                    if (node.subs[2].fragment == Fragment::JUST_0) return std::move(ret) + "and_n(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
968
14
                    return std::move(ret) + "andor(" + std::move(subs[0]) + "," + std::move(subs[1]) + "," + std::move(subs[2]) + ")";
969
14
                case Fragment::MULTI: {
970
14
                    CHECK_NONFATAL(!is_tapscript);
971
14
                    auto str = std::move(ret) + "multi(" + util::ToString(node.k);
972
14
                    for (const auto& key : node.keys) {
973
14
                        auto key_str = toString(key);
974
14
                        if (!key_str) return {};
975
14
                        str += "," + std::move(*key_str);
976
14
                    }
977
14
                    return std::move(str) + ")";
978
14
                }
979
14
                case Fragment::MULTI_A: {
980
14
                    CHECK_NONFATAL(is_tapscript);
981
14
                    auto str = std::move(ret) + "multi_a(" + util::ToString(node.k);
982
14
                    for (const auto& key : node.keys) {
983
14
                        auto key_str = toString(key);
984
14
                        if (!key_str) return {};
985
14
                        str += "," + std::move(*key_str);
986
14
                    }
987
14
                    return std::move(str) + ")";
988
14
                }
989
14
                case Fragment::THRESH: {
990
14
                    auto str = std::move(ret) + "thresh(" + util::ToString(node.k);
991
14
                    for (auto& sub : subs) {
992
14
                        str += "," + std::move(sub);
993
14
                    }
994
14
                    return std::move(str) + ")";
995
14
                }
996
14
                default: break;
997
14
            }
998
14
            assert(false);
999
14
        };
1000
1001
14
        return TreeEvalMaybe<std::string>(false, downfn, upfn);
1002
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
884
1.08k
    std::optional<std::string> ToString(const CTx& ctx, bool& has_priv_key) const {
885
        // To construct the std::string representation for a Miniscript object, we use
886
        // the TreeEvalMaybe algorithm. The State is a boolean: whether the parent node is a
887
        // wrapper. If so, non-wrapper expressions must be prefixed with a ":".
888
1.08k
        auto downfn = [](bool, const Node& node, size_t) {
889
1.08k
            return (node.fragment == Fragment::WRAP_A || node.fragment == Fragment::WRAP_S ||
890
1.08k
                    node.fragment == Fragment::WRAP_D || node.fragment == Fragment::WRAP_V ||
891
1.08k
                    node.fragment == Fragment::WRAP_J || node.fragment == Fragment::WRAP_N ||
892
1.08k
                    node.fragment == Fragment::WRAP_C ||
893
1.08k
                    (node.fragment == Fragment::AND_V && node.subs[1].fragment == Fragment::JUST_1) ||
894
1.08k
                    (node.fragment == Fragment::OR_I && node.subs[0].fragment == Fragment::JUST_0) ||
895
1.08k
                    (node.fragment == Fragment::OR_I && node.subs[1].fragment == Fragment::JUST_0));
896
1.08k
        };
897
1.08k
        auto toString = [&ctx, &has_priv_key](Key key) -> std::optional<std::string> {
898
1.08k
            bool fragment_has_priv_key{false};
899
1.08k
            auto key_str{ctx.ToString(key, fragment_has_priv_key)};
900
1.08k
            if (key_str) has_priv_key = has_priv_key || fragment_has_priv_key;
901
1.08k
            return key_str;
902
1.08k
        };
903
        // The upward function computes for a node, given whether its parent is a wrapper,
904
        // and the string representations of its child nodes, the string representation of the node.
905
1.08k
        const bool is_tapscript{IsTapscript(m_script_ctx)};
906
1.08k
        auto upfn = [is_tapscript, &toString](bool wrapped, const Node& node, std::span<std::string> subs) -> std::optional<std::string> {
907
1.08k
            std::string ret = wrapped ? ":" : "";
908
909
1.08k
            switch (node.fragment) {
910
1.08k
                case Fragment::WRAP_A: return "a" + std::move(subs[0]);
911
1.08k
                case Fragment::WRAP_S: return "s" + std::move(subs[0]);
912
1.08k
                case Fragment::WRAP_C:
913
1.08k
                    if (node.subs[0].fragment == Fragment::PK_K) {
914
                        // pk(K) is syntactic sugar for c:pk_k(K)
915
1.08k
                        auto key_str = toString(node.subs[0].keys[0]);
916
1.08k
                        if (!key_str) return {};
917
1.08k
                        return std::move(ret) + "pk(" + std::move(*key_str) + ")";
918
1.08k
                    }
919
1.08k
                    if (node.subs[0].fragment == Fragment::PK_H) {
920
                        // pkh(K) is syntactic sugar for c:pk_h(K)
921
1.08k
                        auto key_str = toString(node.subs[0].keys[0]);
922
1.08k
                        if (!key_str) return {};
923
1.08k
                        return std::move(ret) + "pkh(" + std::move(*key_str) + ")";
924
1.08k
                    }
925
1.08k
                    return "c" + std::move(subs[0]);
926
1.08k
                case Fragment::WRAP_D: return "d" + std::move(subs[0]);
927
1.08k
                case Fragment::WRAP_V: return "v" + std::move(subs[0]);
928
1.08k
                case Fragment::WRAP_J: return "j" + std::move(subs[0]);
929
1.08k
                case Fragment::WRAP_N: return "n" + std::move(subs[0]);
930
1.08k
                case Fragment::AND_V:
931
                    // t:X is syntactic sugar for and_v(X,1).
932
1.08k
                    if (node.subs[1].fragment == Fragment::JUST_1) return "t" + std::move(subs[0]);
933
1.08k
                    break;
934
1.08k
                case Fragment::OR_I:
935
1.08k
                    if (node.subs[0].fragment == Fragment::JUST_0) return "l" + std::move(subs[1]);
936
1.08k
                    if (node.subs[1].fragment == Fragment::JUST_0) return "u" + std::move(subs[0]);
937
1.08k
                    break;
938
1.08k
                default: break;
939
1.08k
            }
940
1.08k
            switch (node.fragment) {
941
1.08k
                case Fragment::PK_K: {
942
1.08k
                    auto key_str = toString(node.keys[0]);
943
1.08k
                    if (!key_str) return {};
944
1.08k
                    return std::move(ret) + "pk_k(" + std::move(*key_str) + ")";
945
1.08k
                }
946
1.08k
                case Fragment::PK_H: {
947
1.08k
                    auto key_str = toString(node.keys[0]);
948
1.08k
                    if (!key_str) return {};
949
1.08k
                    return std::move(ret) + "pk_h(" + std::move(*key_str) + ")";
950
1.08k
                }
951
1.08k
                case Fragment::AFTER: return std::move(ret) + "after(" + util::ToString(node.k) + ")";
952
1.08k
                case Fragment::OLDER: return std::move(ret) + "older(" + util::ToString(node.k) + ")";
953
1.08k
                case Fragment::HASH256: return std::move(ret) + "hash256(" + HexStr(node.data) + ")";
954
1.08k
                case Fragment::HASH160: return std::move(ret) + "hash160(" + HexStr(node.data) + ")";
955
1.08k
                case Fragment::SHA256: return std::move(ret) + "sha256(" + HexStr(node.data) + ")";
956
1.08k
                case Fragment::RIPEMD160: return std::move(ret) + "ripemd160(" + HexStr(node.data) + ")";
957
1.08k
                case Fragment::JUST_1: return std::move(ret) + "1";
958
1.08k
                case Fragment::JUST_0: return std::move(ret) + "0";
959
1.08k
                case Fragment::AND_V: return std::move(ret) + "and_v(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
960
1.08k
                case Fragment::AND_B: return std::move(ret) + "and_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
961
1.08k
                case Fragment::OR_B: return std::move(ret) + "or_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
962
1.08k
                case Fragment::OR_D: return std::move(ret) + "or_d(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
963
1.08k
                case Fragment::OR_C: return std::move(ret) + "or_c(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
964
1.08k
                case Fragment::OR_I: return std::move(ret) + "or_i(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
965
1.08k
                case Fragment::ANDOR:
966
                    // and_n(X,Y) is syntactic sugar for andor(X,Y,0).
967
1.08k
                    if (node.subs[2].fragment == Fragment::JUST_0) return std::move(ret) + "and_n(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
968
1.08k
                    return std::move(ret) + "andor(" + std::move(subs[0]) + "," + std::move(subs[1]) + "," + std::move(subs[2]) + ")";
969
1.08k
                case Fragment::MULTI: {
970
1.08k
                    CHECK_NONFATAL(!is_tapscript);
971
1.08k
                    auto str = std::move(ret) + "multi(" + util::ToString(node.k);
972
1.08k
                    for (const auto& key : node.keys) {
973
1.08k
                        auto key_str = toString(key);
974
1.08k
                        if (!key_str) return {};
975
1.08k
                        str += "," + std::move(*key_str);
976
1.08k
                    }
977
1.08k
                    return std::move(str) + ")";
978
1.08k
                }
979
1.08k
                case Fragment::MULTI_A: {
980
1.08k
                    CHECK_NONFATAL(is_tapscript);
981
1.08k
                    auto str = std::move(ret) + "multi_a(" + util::ToString(node.k);
982
1.08k
                    for (const auto& key : node.keys) {
983
1.08k
                        auto key_str = toString(key);
984
1.08k
                        if (!key_str) return {};
985
1.08k
                        str += "," + std::move(*key_str);
986
1.08k
                    }
987
1.08k
                    return std::move(str) + ")";
988
1.08k
                }
989
1.08k
                case Fragment::THRESH: {
990
1.08k
                    auto str = std::move(ret) + "thresh(" + util::ToString(node.k);
991
1.08k
                    for (auto& sub : subs) {
992
1.08k
                        str += "," + std::move(sub);
993
1.08k
                    }
994
1.08k
                    return std::move(str) + ")";
995
1.08k
                }
996
1.08k
                default: break;
997
1.08k
            }
998
1.08k
            assert(false);
999
1.08k
        };
1000
1001
1.08k
        return TreeEvalMaybe<std::string>(false, downfn, upfn);
1002
1.08k
    }
1003
1004
private:
1005
9.01M
    internal::Ops CalcOps() const {
1006
9.01M
        switch (fragment) {
1007
245
            case Fragment::JUST_1: return {0, 0, {}};
1008
709
            case Fragment::JUST_0: return {0, {}, 0};
1009
5.50k
            case Fragment::PK_K: return {0, 0, 0};
1010
814
            case Fragment::PK_H: return {3, 0, 0};
1011
7.98k
            case Fragment::OLDER:
1012
9.14k
            case Fragment::AFTER: return {1, 0, {}};
1013
110
            case Fragment::SHA256:
1014
187
            case Fragment::RIPEMD160:
1015
303
            case Fragment::HASH256:
1016
400
            case Fragment::HASH160: return {4, 0, {}};
1017
1.56k
            case Fragment::AND_V: return {subs[0].ops.count + subs[1].ops.count, subs[0].ops.sat + subs[1].ops.sat, {}};
1018
7.19k
            case Fragment::AND_B: {
1019
7.19k
                const auto count{1 + subs[0].ops.count + subs[1].ops.count};
1020
7.19k
                const auto sat{subs[0].ops.sat + subs[1].ops.sat};
1021
7.19k
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1022
7.19k
                return {count, sat, dsat};
1023
303
            }
1024
91
            case Fragment::OR_B: {
1025
91
                const auto count{1 + subs[0].ops.count + subs[1].ops.count};
1026
91
                const auto sat{(subs[0].ops.sat + subs[1].ops.dsat) | (subs[1].ops.sat + subs[0].ops.dsat)};
1027
91
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1028
91
                return {count, sat, dsat};
1029
303
            }
1030
126
            case Fragment::OR_D: {
1031
126
                const auto count{3 + subs[0].ops.count + subs[1].ops.count};
1032
126
                const auto sat{subs[0].ops.sat | (subs[1].ops.sat + subs[0].ops.dsat)};
1033
126
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1034
126
                return {count, sat, dsat};
1035
303
            }
1036
60
            case Fragment::OR_C: {
1037
60
                const auto count{2 + subs[0].ops.count + subs[1].ops.count};
1038
60
                const auto sat{subs[0].ops.sat | (subs[1].ops.sat + subs[0].ops.dsat)};
1039
60
                return {count, sat, {}};
1040
303
            }
1041
645
            case Fragment::OR_I: {
1042
645
                const auto count{3 + subs[0].ops.count + subs[1].ops.count};
1043
645
                const auto sat{subs[0].ops.sat | subs[1].ops.sat};
1044
645
                const auto dsat{subs[0].ops.dsat | subs[1].ops.dsat};
1045
645
                return {count, sat, dsat};
1046
303
            }
1047
260
            case Fragment::ANDOR: {
1048
260
                const auto count{3 + subs[0].ops.count + subs[1].ops.count + subs[2].ops.count};
1049
260
                const auto sat{(subs[1].ops.sat + subs[0].ops.sat) | (subs[0].ops.dsat + subs[2].ops.sat)};
1050
260
                const auto dsat{subs[0].ops.dsat + subs[2].ops.dsat};
1051
260
                return {count, sat, dsat};
1052
303
            }
1053
173
            case Fragment::MULTI: return {1, (uint32_t)keys.size(), (uint32_t)keys.size()};
1054
809
            case Fragment::MULTI_A: return {(uint32_t)keys.size() + 1, 0, 0};
1055
885
            case Fragment::WRAP_S:
1056
7.13k
            case Fragment::WRAP_C:
1057
8.97M
            case Fragment::WRAP_N: return {1 + subs[0].ops.count, subs[0].ops.sat, subs[0].ops.dsat};
1058
7.57k
            case Fragment::WRAP_A: return {2 + subs[0].ops.count, subs[0].ops.sat, subs[0].ops.dsat};
1059
122
            case Fragment::WRAP_D: return {3 + subs[0].ops.count, subs[0].ops.sat, 0};
1060
16
            case Fragment::WRAP_J: return {4 + subs[0].ops.count, subs[0].ops.sat, 0};
1061
1.71k
            case Fragment::WRAP_V: return {subs[0].ops.count + (subs[0].GetType() << "x"_mst), subs[0].ops.sat, {}};
1062
410
            case Fragment::THRESH: {
1063
410
                uint32_t count = 0;
1064
410
                auto sats = Vector(internal::MaxInt<uint32_t>(0));
1065
1.57k
                for (const auto& sub : subs) {
1066
1.57k
                    count += sub.ops.count + 1;
1067
1.57k
                    auto next_sats = Vector(sats[0] + sub.ops.dsat);
1068
4.64k
                    for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub.ops.dsat) | (sats[j - 1] + sub.ops.sat));
1069
1.57k
                    next_sats.push_back(sats[sats.size() - 1] + sub.ops.sat);
1070
1.57k
                    sats = std::move(next_sats);
1071
1.57k
                }
1072
410
                assert(k < sats.size());
1073
410
                return {count, sats[k], sats[0]};
1074
410
            }
1075
9.01M
        }
1076
9.01M
        assert(false);
1077
0
    }
miniscript::Node<CPubKey>::CalcOps() const
Line
Count
Source
1005
28.5k
    internal::Ops CalcOps() const {
1006
28.5k
        switch (fragment) {
1007
232
            case Fragment::JUST_1: return {0, 0, {}};
1008
449
            case Fragment::JUST_0: return {0, {}, 0};
1009
1.69k
            case Fragment::PK_K: return {0, 0, 0};
1010
115
            case Fragment::PK_H: return {3, 0, 0};
1011
7.60k
            case Fragment::OLDER:
1012
7.99k
            case Fragment::AFTER: return {1, 0, {}};
1013
68
            case Fragment::SHA256:
1014
94
            case Fragment::RIPEMD160:
1015
134
            case Fragment::HASH256:
1016
158
            case Fragment::HASH160: return {4, 0, {}};
1017
292
            case Fragment::AND_V: return {subs[0].ops.count + subs[1].ops.count, subs[0].ops.sat + subs[1].ops.sat, {}};
1018
6.85k
            case Fragment::AND_B: {
1019
6.85k
                const auto count{1 + subs[0].ops.count + subs[1].ops.count};
1020
6.85k
                const auto sat{subs[0].ops.sat + subs[1].ops.sat};
1021
6.85k
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1022
6.85k
                return {count, sat, dsat};
1023
134
            }
1024
29
            case Fragment::OR_B: {
1025
29
                const auto count{1 + subs[0].ops.count + subs[1].ops.count};
1026
29
                const auto sat{(subs[0].ops.sat + subs[1].ops.dsat) | (subs[1].ops.sat + subs[0].ops.dsat)};
1027
29
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1028
29
                return {count, sat, dsat};
1029
134
            }
1030
42
            case Fragment::OR_D: {
1031
42
                const auto count{3 + subs[0].ops.count + subs[1].ops.count};
1032
42
                const auto sat{subs[0].ops.sat | (subs[1].ops.sat + subs[0].ops.dsat)};
1033
42
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1034
42
                return {count, sat, dsat};
1035
134
            }
1036
20
            case Fragment::OR_C: {
1037
20
                const auto count{2 + subs[0].ops.count + subs[1].ops.count};
1038
20
                const auto sat{subs[0].ops.sat | (subs[1].ops.sat + subs[0].ops.dsat)};
1039
20
                return {count, sat, {}};
1040
134
            }
1041
391
            case Fragment::OR_I: {
1042
391
                const auto count{3 + subs[0].ops.count + subs[1].ops.count};
1043
391
                const auto sat{subs[0].ops.sat | subs[1].ops.sat};
1044
391
                const auto dsat{subs[0].ops.dsat | subs[1].ops.dsat};
1045
391
                return {count, sat, dsat};
1046
134
            }
1047
124
            case Fragment::ANDOR: {
1048
124
                const auto count{3 + subs[0].ops.count + subs[1].ops.count + subs[2].ops.count};
1049
124
                const auto sat{(subs[1].ops.sat + subs[0].ops.sat) | (subs[0].ops.dsat + subs[2].ops.sat)};
1050
124
                const auto dsat{subs[0].ops.dsat + subs[2].ops.dsat};
1051
124
                return {count, sat, dsat};
1052
134
            }
1053
49
            case Fragment::MULTI: return {1, (uint32_t)keys.size(), (uint32_t)keys.size()};
1054
5
            case Fragment::MULTI_A: return {(uint32_t)keys.size() + 1, 0, 0};
1055
471
            case Fragment::WRAP_S:
1056
2.24k
            case Fragment::WRAP_C:
1057
2.54k
            case Fragment::WRAP_N: return {1 + subs[0].ops.count, subs[0].ops.sat, subs[0].ops.dsat};
1058
6.96k
            case Fragment::WRAP_A: return {2 + subs[0].ops.count, subs[0].ops.sat, subs[0].ops.dsat};
1059
44
            case Fragment::WRAP_D: return {3 + subs[0].ops.count, subs[0].ops.sat, 0};
1060
16
            case Fragment::WRAP_J: return {4 + subs[0].ops.count, subs[0].ops.sat, 0};
1061
356
            case Fragment::WRAP_V: return {subs[0].ops.count + (subs[0].GetType() << "x"_mst), subs[0].ops.sat, {}};
1062
140
            case Fragment::THRESH: {
1063
140
                uint32_t count = 0;
1064
140
                auto sats = Vector(internal::MaxInt<uint32_t>(0));
1065
679
                for (const auto& sub : subs) {
1066
679
                    count += sub.ops.count + 1;
1067
679
                    auto next_sats = Vector(sats[0] + sub.ops.dsat);
1068
2.35k
                    for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub.ops.dsat) | (sats[j - 1] + sub.ops.sat));
1069
679
                    next_sats.push_back(sats[sats.size() - 1] + sub.ops.sat);
1070
679
                    sats = std::move(next_sats);
1071
679
                }
1072
140
                assert(k < sats.size());
1073
140
                return {count, sats[k], sats[0]};
1074
140
            }
1075
28.5k
        }
1076
28.5k
        assert(false);
1077
0
    }
miniscript::Node<unsigned int>::CalcOps() const
Line
Count
Source
1005
1.72M
    internal::Ops CalcOps() const {
1006
1.72M
        switch (fragment) {
1007
13
            case Fragment::JUST_1: return {0, 0, {}};
1008
260
            case Fragment::JUST_0: return {0, {}, 0};
1009
1.44k
            case Fragment::PK_K: return {0, 0, 0};
1010
475
            case Fragment::PK_H: return {3, 0, 0};
1011
322
            case Fragment::OLDER:
1012
661
            case Fragment::AFTER: return {1, 0, {}};
1013
42
            case Fragment::SHA256:
1014
93
            case Fragment::RIPEMD160:
1015
157
            case Fragment::HASH256:
1016
230
            case Fragment::HASH160: return {4, 0, {}};
1017
724
            case Fragment::AND_V: return {subs[0].ops.count + subs[1].ops.count, subs[0].ops.sat + subs[1].ops.sat, {}};
1018
249
            case Fragment::AND_B: {
1019
249
                const auto count{1 + subs[0].ops.count + subs[1].ops.count};
1020
249
                const auto sat{subs[0].ops.sat + subs[1].ops.sat};
1021
249
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1022
249
                return {count, sat, dsat};
1023
157
            }
1024
62
            case Fragment::OR_B: {
1025
62
                const auto count{1 + subs[0].ops.count + subs[1].ops.count};
1026
62
                const auto sat{(subs[0].ops.sat + subs[1].ops.dsat) | (subs[1].ops.sat + subs[0].ops.dsat)};
1027
62
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1028
62
                return {count, sat, dsat};
1029
157
            }
1030
84
            case Fragment::OR_D: {
1031
84
                const auto count{3 + subs[0].ops.count + subs[1].ops.count};
1032
84
                const auto sat{subs[0].ops.sat | (subs[1].ops.sat + subs[0].ops.dsat)};
1033
84
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1034
84
                return {count, sat, dsat};
1035
157
            }
1036
40
            case Fragment::OR_C: {
1037
40
                const auto count{2 + subs[0].ops.count + subs[1].ops.count};
1038
40
                const auto sat{subs[0].ops.sat | (subs[1].ops.sat + subs[0].ops.dsat)};
1039
40
                return {count, sat, {}};
1040
157
            }
1041
254
            case Fragment::OR_I: {
1042
254
                const auto count{3 + subs[0].ops.count + subs[1].ops.count};
1043
254
                const auto sat{subs[0].ops.sat | subs[1].ops.sat};
1044
254
                const auto dsat{subs[0].ops.dsat | subs[1].ops.dsat};
1045
254
                return {count, sat, dsat};
1046
157
            }
1047
136
            case Fragment::ANDOR: {
1048
136
                const auto count{3 + subs[0].ops.count + subs[1].ops.count + subs[2].ops.count};
1049
136
                const auto sat{(subs[1].ops.sat + subs[0].ops.sat) | (subs[0].ops.dsat + subs[2].ops.sat)};
1050
136
                const auto dsat{subs[0].ops.dsat + subs[2].ops.dsat};
1051
136
                return {count, sat, dsat};
1052
157
            }
1053
124
            case Fragment::MULTI: return {1, (uint32_t)keys.size(), (uint32_t)keys.size()};
1054
32
            case Fragment::MULTI_A: return {(uint32_t)keys.size() + 1, 0, 0};
1055
386
            case Fragment::WRAP_S:
1056
2.28k
            case Fragment::WRAP_C:
1057
1.72M
            case Fragment::WRAP_N: return {1 + subs[0].ops.count, subs[0].ops.sat, subs[0].ops.dsat};
1058
495
            case Fragment::WRAP_A: return {2 + subs[0].ops.count, subs[0].ops.sat, subs[0].ops.dsat};
1059
72
            case Fragment::WRAP_D: return {3 + subs[0].ops.count, subs[0].ops.sat, 0};
1060
0
            case Fragment::WRAP_J: return {4 + subs[0].ops.count, subs[0].ops.sat, 0};
1061
801
            case Fragment::WRAP_V: return {subs[0].ops.count + (subs[0].GetType() << "x"_mst), subs[0].ops.sat, {}};
1062
242
            case Fragment::THRESH: {
1063
242
                uint32_t count = 0;
1064
242
                auto sats = Vector(internal::MaxInt<uint32_t>(0));
1065
814
                for (const auto& sub : subs) {
1066
814
                    count += sub.ops.count + 1;
1067
814
                    auto next_sats = Vector(sats[0] + sub.ops.dsat);
1068
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));
1069
814
                    next_sats.push_back(sats[sats.size() - 1] + sub.ops.sat);
1070
814
                    sats = std::move(next_sats);
1071
814
                }
1072
242
                assert(k < sats.size());
1073
242
                return {count, sats[k], sats[0]};
1074
242
            }
1075
1.72M
        }
1076
1.72M
        assert(false);
1077
0
    }
miniscript::Node<XOnlyPubKey>::CalcOps() const
Line
Count
Source
1005
7.25M
    internal::Ops CalcOps() const {
1006
7.25M
        switch (fragment) {
1007
0
            case Fragment::JUST_1: return {0, 0, {}};
1008
0
            case Fragment::JUST_0: return {0, {}, 0};
1009
2.36k
            case Fragment::PK_K: return {0, 0, 0};
1010
224
            case Fragment::PK_H: return {3, 0, 0};
1011
60
            case Fragment::OLDER:
1012
488
            case Fragment::AFTER: return {1, 0, {}};
1013
0
            case Fragment::SHA256:
1014
0
            case Fragment::RIPEMD160:
1015
12
            case Fragment::HASH256:
1016
12
            case Fragment::HASH160: return {4, 0, {}};
1017
552
            case Fragment::AND_V: return {subs[0].ops.count + subs[1].ops.count, subs[0].ops.sat + subs[1].ops.sat, {}};
1018
88
            case Fragment::AND_B: {
1019
88
                const auto count{1 + subs[0].ops.count + subs[1].ops.count};
1020
88
                const auto sat{subs[0].ops.sat + subs[1].ops.sat};
1021
88
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1022
88
                return {count, sat, dsat};
1023
12
            }
1024
0
            case Fragment::OR_B: {
1025
0
                const auto count{1 + subs[0].ops.count + subs[1].ops.count};
1026
0
                const auto sat{(subs[0].ops.sat + subs[1].ops.dsat) | (subs[1].ops.sat + subs[0].ops.dsat)};
1027
0
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1028
0
                return {count, sat, dsat};
1029
12
            }
1030
0
            case Fragment::OR_D: {
1031
0
                const auto count{3 + subs[0].ops.count + subs[1].ops.count};
1032
0
                const auto sat{subs[0].ops.sat | (subs[1].ops.sat + subs[0].ops.dsat)};
1033
0
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1034
0
                return {count, sat, dsat};
1035
12
            }
1036
0
            case Fragment::OR_C: {
1037
0
                const auto count{2 + subs[0].ops.count + subs[1].ops.count};
1038
0
                const auto sat{subs[0].ops.sat | (subs[1].ops.sat + subs[0].ops.dsat)};
1039
0
                return {count, sat, {}};
1040
12
            }
1041
0
            case Fragment::OR_I: {
1042
0
                const auto count{3 + subs[0].ops.count + subs[1].ops.count};
1043
0
                const auto sat{subs[0].ops.sat | subs[1].ops.sat};
1044
0
                const auto dsat{subs[0].ops.dsat | subs[1].ops.dsat};
1045
0
                return {count, sat, dsat};
1046
12
            }
1047
0
            case Fragment::ANDOR: {
1048
0
                const auto count{3 + subs[0].ops.count + subs[1].ops.count + subs[2].ops.count};
1049
0
                const auto sat{(subs[1].ops.sat + subs[0].ops.sat) | (subs[0].ops.dsat + subs[2].ops.sat)};
1050
0
                const auto dsat{subs[0].ops.dsat + subs[2].ops.dsat};
1051
0
                return {count, sat, dsat};
1052
12
            }
1053
0
            case Fragment::MULTI: return {1, (uint32_t)keys.size(), (uint32_t)keys.size()};
1054
772
            case Fragment::MULTI_A: return {(uint32_t)keys.size() + 1, 0, 0};
1055
28
            case Fragment::WRAP_S:
1056
2.61k
            case Fragment::WRAP_C:
1057
7.25M
            case Fragment::WRAP_N: return {1 + subs[0].ops.count, subs[0].ops.sat, subs[0].ops.dsat};
1058
116
            case Fragment::WRAP_A: return {2 + subs[0].ops.count, subs[0].ops.sat, subs[0].ops.dsat};
1059
6
            case Fragment::WRAP_D: return {3 + subs[0].ops.count, subs[0].ops.sat, 0};
1060
0
            case Fragment::WRAP_J: return {4 + subs[0].ops.count, subs[0].ops.sat, 0};
1061
558
            case Fragment::WRAP_V: return {subs[0].ops.count + (subs[0].GetType() << "x"_mst), subs[0].ops.sat, {}};
1062
28
            case Fragment::THRESH: {
1063
28
                uint32_t count = 0;
1064
28
                auto sats = Vector(internal::MaxInt<uint32_t>(0));
1065
84
                for (const auto& sub : subs) {
1066
84
                    count += sub.ops.count + 1;
1067
84
                    auto next_sats = Vector(sats[0] + sub.ops.dsat);
1068
168
                    for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub.ops.dsat) | (sats[j - 1] + sub.ops.sat));
1069
84
                    next_sats.push_back(sats[sats.size() - 1] + sub.ops.sat);
1070
84
                    sats = std::move(next_sats);
1071
84
                }
1072
28
                assert(k < sats.size());
1073
28
                return {count, sats[k], sats[0]};
1074
28
            }
1075
7.25M
        }
1076
7.25M
        assert(false);
1077
0
    }
1078
1079
9.01M
    internal::StackSize CalcStackSize() const {
1080
9.01M
        using namespace internal;
1081
9.01M
        switch (fragment) {
1082
709
            case Fragment::JUST_0: return {{}, SatInfo::Push()};
1083
245
            case Fragment::JUST_1: return {SatInfo::Push(), {}};
1084
7.98k
            case Fragment::OLDER:
1085
9.14k
            case Fragment::AFTER: return {SatInfo::Push() + SatInfo::Nop(), {}};
1086
5.50k
            case Fragment::PK_K: return {SatInfo::Push()};
1087
814
            case Fragment::PK_H: return {SatInfo::OP_DUP() + SatInfo::Hash() + SatInfo::Push() + SatInfo::OP_EQUALVERIFY()};
1088
110
            case Fragment::SHA256:
1089
187
            case Fragment::RIPEMD160:
1090
303
            case Fragment::HASH256:
1091
400
            case Fragment::HASH160: return {
1092
400
                SatInfo::OP_SIZE() + SatInfo::Push() + SatInfo::OP_EQUALVERIFY() + SatInfo::Hash() + SatInfo::Push() + SatInfo::OP_EQUAL(),
1093
400
                {}
1094
400
            };
1095
260
            case Fragment::ANDOR: {
1096
260
                const auto& x{subs[0].ss};
1097
260
                const auto& y{subs[1].ss};
1098
260
                const auto& z{subs[2].ss};
1099
260
                return {
1100
260
                    (x.Sat() + SatInfo::If() + y.Sat()) | (x.Dsat() + SatInfo::If() + z.Sat()),
1101
260
                    x.Dsat() + SatInfo::If() + z.Dsat()
1102
260
                };
1103
303
            }
1104
1.56k
            case Fragment::AND_V: {
1105
1.56k
                const auto& x{subs[0].ss};
1106
1.56k
                const auto& y{subs[1].ss};
1107
1.56k
                return {x.Sat() + y.Sat(), {}};
1108
303
            }
1109
7.19k
            case Fragment::AND_B: {
1110
7.19k
                const auto& x{subs[0].ss};
1111
7.19k
                const auto& y{subs[1].ss};
1112
7.19k
                return {x.Sat() + y.Sat() + SatInfo::BinaryOp(), x.Dsat() + y.Dsat() + SatInfo::BinaryOp()};
1113
303
            }
1114
91
            case Fragment::OR_B: {
1115
91
                const auto& x{subs[0].ss};
1116
91
                const auto& y{subs[1].ss};
1117
91
                return {
1118
91
                    ((x.Sat() + y.Dsat()) | (x.Dsat() + y.Sat())) + SatInfo::BinaryOp(),
1119
91
                    x.Dsat() + y.Dsat() + SatInfo::BinaryOp()
1120
91
                };
1121
303
            }
1122
60
            case Fragment::OR_C: {
1123
60
                const auto& x{subs[0].ss};
1124
60
                const auto& y{subs[1].ss};
1125
60
                return {(x.Sat() + SatInfo::If()) | (x.Dsat() + SatInfo::If() + y.Sat()), {}};
1126
303
            }
1127
126
            case Fragment::OR_D: {
1128
126
                const auto& x{subs[0].ss};
1129
126
                const auto& y{subs[1].ss};
1130
126
                return {
1131
126
                    (x.Sat() + SatInfo::OP_IFDUP(true) + SatInfo::If()) | (x.Dsat() + SatInfo::OP_IFDUP(false) + SatInfo::If() + y.Sat()),
1132
126
                    x.Dsat() + SatInfo::OP_IFDUP(false) + SatInfo::If() + y.Dsat()
1133
126
                };
1134
303
            }
1135
645
            case Fragment::OR_I: {
1136
645
                const auto& x{subs[0].ss};
1137
645
                const auto& y{subs[1].ss};
1138
645
                return {SatInfo::If() + (x.Sat() | y.Sat()), SatInfo::If() + (x.Dsat() | y.Dsat())};
1139
303
            }
1140
            // multi(k, key1, key2, ..., key_n) starts off with k+1 stack elements (a 0, plus k
1141
            // signatures), then reaches n+k+3 stack elements after pushing the n keys, plus k and
1142
            // n itself, and ends with 1 stack element (success or failure). Thus, it net removes
1143
            // k elements (from k+1 to 1), while reaching k+n+2 more than it ends with.
1144
173
            case Fragment::MULTI: return {SatInfo(k, k + keys.size() + 2)};
1145
            // multi_a(k, key1, key2, ..., key_n) starts off with n stack elements (the
1146
            // signatures), reaches 1 more (after the first key push), and ends with 1. Thus it net
1147
            // removes n-1 elements (from n to 1) while reaching n more than it ends with.
1148
809
            case Fragment::MULTI_A: return {SatInfo(keys.size() - 1, keys.size())};
1149
7.57k
            case Fragment::WRAP_A:
1150
8.97M
            case Fragment::WRAP_N:
1151
8.97M
            case Fragment::WRAP_S: return subs[0].ss;
1152
6.25k
            case Fragment::WRAP_C: return {
1153
6.25k
                subs[0].ss.Sat() + SatInfo::OP_CHECKSIG(),
1154
6.25k
                subs[0].ss.Dsat() + SatInfo::OP_CHECKSIG()
1155
6.25k
            };
1156
122
            case Fragment::WRAP_D: return {
1157
122
                SatInfo::OP_DUP() + SatInfo::If() + subs[0].ss.Sat(),
1158
122
                SatInfo::OP_DUP() + SatInfo::If()
1159
122
            };
1160
1.71k
            case Fragment::WRAP_V: return {subs[0].ss.Sat() + SatInfo::OP_VERIFY(), {}};
1161
16
            case Fragment::WRAP_J: return {
1162
16
                SatInfo::OP_SIZE() + SatInfo::OP_0NOTEQUAL() + SatInfo::If() + subs[0].ss.Sat(),
1163
16
                SatInfo::OP_SIZE() + SatInfo::OP_0NOTEQUAL() + SatInfo::If()
1164
16
            };
1165
410
            case Fragment::THRESH: {
1166
                // sats[j] is the SatInfo corresponding to all traces reaching j satisfactions.
1167
410
                auto sats = Vector(SatInfo::Empty());
1168
1.98k
                for (size_t i = 0; i < subs.size(); ++i) {
1169
                    // Loop over the subexpressions, processing them one by one. After adding
1170
                    // element i we need to add OP_ADD (if i>0).
1171
1.57k
                    auto add = i ? SatInfo::BinaryOp() : SatInfo::Empty();
1172
                    // Construct a variable that will become the next sats, starting with index 0.
1173
1.57k
                    auto next_sats = Vector(sats[0] + subs[i].ss.Dsat() + add);
1174
                    // Then loop to construct next_sats[1..i].
1175
4.64k
                    for (size_t j = 1; j < sats.size(); ++j) {
1176
3.07k
                        next_sats.push_back(((sats[j] + subs[i].ss.Dsat()) | (sats[j - 1] + subs[i].ss.Sat())) + add);
1177
3.07k
                    }
1178
                    // Finally construct next_sats[i+1].
1179
1.57k
                    next_sats.push_back(sats[sats.size() - 1] + subs[i].ss.Sat() + add);
1180
                    // Switch over.
1181
1.57k
                    sats = std::move(next_sats);
1182
1.57k
                }
1183
                // To satisfy thresh we need k satisfactions; to dissatisfy we need 0. In both
1184
                // cases a push of k and an OP_EQUAL follow.
1185
410
                return {
1186
410
                    sats[k] + SatInfo::Push() + SatInfo::OP_EQUAL(),
1187
410
                    sats[0] + SatInfo::Push() + SatInfo::OP_EQUAL()
1188
410
                };
1189
8.97M
            }
1190
9.01M
        }
1191
9.01M
        assert(false);
1192
0
    }
miniscript::Node<CPubKey>::CalcStackSize() const
Line
Count
Source
1079
28.5k
    internal::StackSize CalcStackSize() const {
1080
28.5k
        using namespace internal;
1081
28.5k
        switch (fragment) {
1082
449
            case Fragment::JUST_0: return {{}, SatInfo::Push()};
1083
232
            case Fragment::JUST_1: return {SatInfo::Push(), {}};
1084
7.60k
            case Fragment::OLDER:
1085
7.99k
            case Fragment::AFTER: return {SatInfo::Push() + SatInfo::Nop(), {}};
1086
1.69k
            case Fragment::PK_K: return {SatInfo::Push()};
1087
115
            case Fragment::PK_H: return {SatInfo::OP_DUP() + SatInfo::Hash() + SatInfo::Push() + SatInfo::OP_EQUALVERIFY()};
1088
68
            case Fragment::SHA256:
1089
94
            case Fragment::RIPEMD160:
1090
134
            case Fragment::HASH256:
1091
158
            case Fragment::HASH160: return {
1092
158
                SatInfo::OP_SIZE() + SatInfo::Push() + SatInfo::OP_EQUALVERIFY() + SatInfo::Hash() + SatInfo::Push() + SatInfo::OP_EQUAL(),
1093
158
                {}
1094
158
            };
1095
124
            case Fragment::ANDOR: {
1096
124
                const auto& x{subs[0].ss};
1097
124
                const auto& y{subs[1].ss};
1098
124
                const auto& z{subs[2].ss};
1099
124
                return {
1100
124
                    (x.Sat() + SatInfo::If() + y.Sat()) | (x.Dsat() + SatInfo::If() + z.Sat()),
1101
124
                    x.Dsat() + SatInfo::If() + z.Dsat()
1102
124
                };
1103
134
            }
1104
292
            case Fragment::AND_V: {
1105
292
                const auto& x{subs[0].ss};
1106
292
                const auto& y{subs[1].ss};
1107
292
                return {x.Sat() + y.Sat(), {}};
1108
134
            }
1109
6.85k
            case Fragment::AND_B: {
1110
6.85k
                const auto& x{subs[0].ss};
1111
6.85k
                const auto& y{subs[1].ss};
1112
6.85k
                return {x.Sat() + y.Sat() + SatInfo::BinaryOp(), x.Dsat() + y.Dsat() + SatInfo::BinaryOp()};
1113
134
            }
1114
29
            case Fragment::OR_B: {
1115
29
                const auto& x{subs[0].ss};
1116
29
                const auto& y{subs[1].ss};
1117
29
                return {
1118
29
                    ((x.Sat() + y.Dsat()) | (x.Dsat() + y.Sat())) + SatInfo::BinaryOp(),
1119
29
                    x.Dsat() + y.Dsat() + SatInfo::BinaryOp()
1120
29
                };
1121
134
            }
1122
20
            case Fragment::OR_C: {
1123
20
                const auto& x{subs[0].ss};
1124
20
                const auto& y{subs[1].ss};
1125
20
                return {(x.Sat() + SatInfo::If()) | (x.Dsat() + SatInfo::If() + y.Sat()), {}};
1126
134
            }
1127
42
            case Fragment::OR_D: {
1128
42
                const auto& x{subs[0].ss};
1129
42
                const auto& y{subs[1].ss};
1130
42
                return {
1131
42
                    (x.Sat() + SatInfo::OP_IFDUP(true) + SatInfo::If()) | (x.Dsat() + SatInfo::OP_IFDUP(false) + SatInfo::If() + y.Sat()),
1132
42
                    x.Dsat() + SatInfo::OP_IFDUP(false) + SatInfo::If() + y.Dsat()
1133
42
                };
1134
134
            }
1135
391
            case Fragment::OR_I: {
1136
391
                const auto& x{subs[0].ss};
1137
391
                const auto& y{subs[1].ss};
1138
391
                return {SatInfo::If() + (x.Sat() | y.Sat()), SatInfo::If() + (x.Dsat() | y.Dsat())};
1139
134
            }
1140
            // multi(k, key1, key2, ..., key_n) starts off with k+1 stack elements (a 0, plus k
1141
            // signatures), then reaches n+k+3 stack elements after pushing the n keys, plus k and
1142
            // n itself, and ends with 1 stack element (success or failure). Thus, it net removes
1143
            // k elements (from k+1 to 1), while reaching k+n+2 more than it ends with.
1144
49
            case Fragment::MULTI: return {SatInfo(k, k + keys.size() + 2)};
1145
            // multi_a(k, key1, key2, ..., key_n) starts off with n stack elements (the
1146
            // signatures), reaches 1 more (after the first key push), and ends with 1. Thus it net
1147
            // removes n-1 elements (from n to 1) while reaching n more than it ends with.
1148
5
            case Fragment::MULTI_A: return {SatInfo(keys.size() - 1, keys.size())};
1149
6.96k
            case Fragment::WRAP_A:
1150
7.27k
            case Fragment::WRAP_N:
1151
7.74k
            case Fragment::WRAP_S: return subs[0].ss;
1152
1.76k
            case Fragment::WRAP_C: return {
1153
1.76k
                subs[0].ss.Sat() + SatInfo::OP_CHECKSIG(),
1154
1.76k
                subs[0].ss.Dsat() + SatInfo::OP_CHECKSIG()
1155
1.76k
            };
1156
44
            case Fragment::WRAP_D: return {
1157
44
                SatInfo::OP_DUP() + SatInfo::If() + subs[0].ss.Sat(),
1158
44
                SatInfo::OP_DUP() + SatInfo::If()
1159
44
            };
1160
356
            case Fragment::WRAP_V: return {subs[0].ss.Sat() + SatInfo::OP_VERIFY(), {}};
1161
16
            case Fragment::WRAP_J: return {
1162
16
                SatInfo::OP_SIZE() + SatInfo::OP_0NOTEQUAL() + SatInfo::If() + subs[0].ss.Sat(),
1163
16
                SatInfo::OP_SIZE() + SatInfo::OP_0NOTEQUAL() + SatInfo::If()
1164
16
            };
1165
140
            case Fragment::THRESH: {
1166
                // sats[j] is the SatInfo corresponding to all traces reaching j satisfactions.
1167
140
                auto sats = Vector(SatInfo::Empty());
1168
819
                for (size_t i = 0; i < subs.size(); ++i) {
1169
                    // Loop over the subexpressions, processing them one by one. After adding
1170
                    // element i we need to add OP_ADD (if i>0).
1171
679
                    auto add = i ? SatInfo::BinaryOp() : SatInfo::Empty();
1172
                    // Construct a variable that will become the next sats, starting with index 0.
1173
679
                    auto next_sats = Vector(sats[0] + subs[i].ss.Dsat() + add);
1174
                    // Then loop to construct next_sats[1..i].
1175
2.35k
                    for (size_t j = 1; j < sats.size(); ++j) {
1176
1.67k
                        next_sats.push_back(((sats[j] + subs[i].ss.Dsat()) | (sats[j - 1] + subs[i].ss.Sat())) + add);
1177
1.67k
                    }
1178
                    // Finally construct next_sats[i+1].
1179
679
                    next_sats.push_back(sats[sats.size() - 1] + subs[i].ss.Sat() + add);
1180
                    // Switch over.
1181
679
                    sats = std::move(next_sats);
1182
679
                }
1183
                // To satisfy thresh we need k satisfactions; to dissatisfy we need 0. In both
1184
                // cases a push of k and an OP_EQUAL follow.
1185
140
                return {
1186
140
                    sats[k] + SatInfo::Push() + SatInfo::OP_EQUAL(),
1187
140
                    sats[0] + SatInfo::Push() + SatInfo::OP_EQUAL()
1188
140
                };
1189
7.27k
            }
1190
28.5k
        }
1191
28.5k
        assert(false);
1192
0
    }
miniscript::Node<unsigned int>::CalcStackSize() const
Line
Count
Source
1079
1.72M
    internal::StackSize CalcStackSize() const {
1080
1.72M
        using namespace internal;
1081
1.72M
        switch (fragment) {
1082
260
            case Fragment::JUST_0: return {{}, SatInfo::Push()};
1083
13
            case Fragment::JUST_1: return {SatInfo::Push(), {}};
1084
322
            case Fragment::OLDER:
1085
661
            case Fragment::AFTER: return {SatInfo::Push() + SatInfo::Nop(), {}};
1086
1.44k
            case Fragment::PK_K: return {SatInfo::Push()};
1087
475
            case Fragment::PK_H: return {SatInfo::OP_DUP() + SatInfo::Hash() + SatInfo::Push() + SatInfo::OP_EQUALVERIFY()};
1088
42
            case Fragment::SHA256:
1089
93
            case Fragment::RIPEMD160:
1090
157
            case Fragment::HASH256:
1091
230
            case Fragment::HASH160: return {
1092
230
                SatInfo::OP_SIZE() + SatInfo::Push() + SatInfo::OP_EQUALVERIFY() + SatInfo::Hash() + SatInfo::Push() + SatInfo::OP_EQUAL(),
1093
230
                {}
1094
230
            };
1095
136
            case Fragment::ANDOR: {
1096
136
                const auto& x{subs[0].ss};
1097
136
                const auto& y{subs[1].ss};
1098
136
                const auto& z{subs[2].ss};
1099
136
                return {
1100
136
                    (x.Sat() + SatInfo::If() + y.Sat()) | (x.Dsat() + SatInfo::If() + z.Sat()),
1101
136
                    x.Dsat() + SatInfo::If() + z.Dsat()
1102
136
                };
1103
157
            }
1104
724
            case Fragment::AND_V: {
1105
724
                const auto& x{subs[0].ss};
1106
724
                const auto& y{subs[1].ss};
1107
724
                return {x.Sat() + y.Sat(), {}};
1108
157
            }
1109
249
            case Fragment::AND_B: {
1110
249
                const auto& x{subs[0].ss};
1111
249
                const auto& y{subs[1].ss};
1112
249
                return {x.Sat() + y.Sat() + SatInfo::BinaryOp(), x.Dsat() + y.Dsat() + SatInfo::BinaryOp()};
1113
157
            }
1114
62
            case Fragment::OR_B: {
1115
62
                const auto& x{subs[0].ss};
1116
62
                const auto& y{subs[1].ss};
1117
62
                return {
1118
62
                    ((x.Sat() + y.Dsat()) | (x.Dsat() + y.Sat())) + SatInfo::BinaryOp(),
1119
62
                    x.Dsat() + y.Dsat() + SatInfo::BinaryOp()
1120
62
                };
1121
157
            }
1122
40
            case Fragment::OR_C: {
1123
40
                const auto& x{subs[0].ss};
1124
40
                const auto& y{subs[1].ss};
1125
40
                return {(x.Sat() + SatInfo::If()) | (x.Dsat() + SatInfo::If() + y.Sat()), {}};
1126
157
            }
1127
84
            case Fragment::OR_D: {
1128
84
                const auto& x{subs[0].ss};
1129
84
                const auto& y{subs[1].ss};
1130
84
                return {
1131
84
                    (x.Sat() + SatInfo::OP_IFDUP(true) + SatInfo::If()) | (x.Dsat() + SatInfo::OP_IFDUP(false) + SatInfo::If() + y.Sat()),
1132
84
                    x.Dsat() + SatInfo::OP_IFDUP(false) + SatInfo::If() + y.Dsat()
1133
84
                };
1134
157
            }
1135
254
            case Fragment::OR_I: {
1136
254
                const auto& x{subs[0].ss};
1137
254
                const auto& y{subs[1].ss};
1138
254
                return {SatInfo::If() + (x.Sat() | y.Sat()), SatInfo::If() + (x.Dsat() | y.Dsat())};
1139
157
            }
1140
            // multi(k, key1, key2, ..., key_n) starts off with k+1 stack elements (a 0, plus k
1141
            // signatures), then reaches n+k+3 stack elements after pushing the n keys, plus k and
1142
            // n itself, and ends with 1 stack element (success or failure). Thus, it net removes
1143
            // k elements (from k+1 to 1), while reaching k+n+2 more than it ends with.
1144
124
            case Fragment::MULTI: return {SatInfo(k, k + keys.size() + 2)};
1145
            // multi_a(k, key1, key2, ..., key_n) starts off with n stack elements (the
1146
            // signatures), reaches 1 more (after the first key push), and ends with 1. Thus it net
1147
            // removes n-1 elements (from n to 1) while reaching n more than it ends with.
1148
32
            case Fragment::MULTI_A: return {SatInfo(keys.size() - 1, keys.size())};
1149
495
            case Fragment::WRAP_A:
1150
1.71M
            case Fragment::WRAP_N:
1151
1.71M
            case Fragment::WRAP_S: return subs[0].ss;
1152
1.89k
            case Fragment::WRAP_C: return {
1153
1.89k
                subs[0].ss.Sat() + SatInfo::OP_CHECKSIG(),
1154
1.89k
                subs[0].ss.Dsat() + SatInfo::OP_CHECKSIG()
1155
1.89k
            };
1156
72
            case Fragment::WRAP_D: return {
1157
72
                SatInfo::OP_DUP() + SatInfo::If() + subs[0].ss.Sat(),
1158
72
                SatInfo::OP_DUP() + SatInfo::If()
1159
72
            };
1160
801
            case Fragment::WRAP_V: return {subs[0].ss.Sat() + SatInfo::OP_VERIFY(), {}};
1161
0
            case Fragment::WRAP_J: return {
1162
0
                SatInfo::OP_SIZE() + SatInfo::OP_0NOTEQUAL() + SatInfo::If() + subs[0].ss.Sat(),
1163
0
                SatInfo::OP_SIZE() + SatInfo::OP_0NOTEQUAL() + SatInfo::If()
1164
0
            };
1165
242
            case Fragment::THRESH: {
1166
                // sats[j] is the SatInfo corresponding to all traces reaching j satisfactions.
1167
242
                auto sats = Vector(SatInfo::Empty());
1168
1.05k
                for (size_t i = 0; i < subs.size(); ++i) {
1169
                    // Loop over the subexpressions, processing them one by one. After adding
1170
                    // element i we need to add OP_ADD (if i>0).
1171
814
                    auto add = i ? SatInfo::BinaryOp() : SatInfo::Empty();
1172
                    // Construct a variable that will become the next sats, starting with index 0.
1173
814
                    auto next_sats = Vector(sats[0] + subs[i].ss.Dsat() + add);
1174
                    // Then loop to construct next_sats[1..i].
1175
2.12k
                    for (size_t j = 1; j < sats.size(); ++j) {
1176
1.31k
                        next_sats.push_back(((sats[j] + subs[i].ss.Dsat()) | (sats[j - 1] + subs[i].ss.Sat())) + add);
1177
1.31k
                    }
1178
                    // Finally construct next_sats[i+1].
1179
814
                    next_sats.push_back(sats[sats.size() - 1] + subs[i].ss.Sat() + add);
1180
                    // Switch over.
1181
814
                    sats = std::move(next_sats);
1182
814
                }
1183
                // To satisfy thresh we need k satisfactions; to dissatisfy we need 0. In both
1184
                // cases a push of k and an OP_EQUAL follow.
1185
242
                return {
1186
242
                    sats[k] + SatInfo::Push() + SatInfo::OP_EQUAL(),
1187
242
                    sats[0] + SatInfo::Push() + SatInfo::OP_EQUAL()
1188
242
                };
1189
1.71M
            }
1190
1.72M
        }
1191
1.72M
        assert(false);
1192
0
    }
miniscript::Node<XOnlyPubKey>::CalcStackSize() const
Line
Count
Source
1079
7.25M
    internal::StackSize CalcStackSize() const {
1080
7.25M
        using namespace internal;
1081
7.25M
        switch (fragment) {
1082
0
            case Fragment::JUST_0: return {{}, SatInfo::Push()};
1083
0
            case Fragment::JUST_1: return {SatInfo::Push(), {}};
1084
60
            case Fragment::OLDER:
1085
488
            case Fragment::AFTER: return {SatInfo::Push() + SatInfo::Nop(), {}};
1086
2.36k
            case Fragment::PK_K: return {SatInfo::Push()};
1087
224
            case Fragment::PK_H: return {SatInfo::OP_DUP() + SatInfo::Hash() + SatInfo::Push() + SatInfo::OP_EQUALVERIFY()};
1088
0
            case Fragment::SHA256:
1089
0
            case Fragment::RIPEMD160:
1090
12
            case Fragment::HASH256:
1091
12
            case Fragment::HASH160: return {
1092
12
                SatInfo::OP_SIZE() + SatInfo::Push() + SatInfo::OP_EQUALVERIFY() + SatInfo::Hash() + SatInfo::Push() + SatInfo::OP_EQUAL(),
1093
12
                {}
1094
12
            };
1095
0
            case Fragment::ANDOR: {
1096
0
                const auto& x{subs[0].ss};
1097
0
                const auto& y{subs[1].ss};
1098
0
                const auto& z{subs[2].ss};
1099
0
                return {
1100
0
                    (x.Sat() + SatInfo::If() + y.Sat()) | (x.Dsat() + SatInfo::If() + z.Sat()),
1101
0
                    x.Dsat() + SatInfo::If() + z.Dsat()
1102
0
                };
1103
12
            }
1104
552
            case Fragment::AND_V: {
1105
552
                const auto& x{subs[0].ss};
1106
552
                const auto& y{subs[1].ss};
1107
552
                return {x.Sat() + y.Sat(), {}};
1108
12
            }
1109
88
            case Fragment::AND_B: {
1110
88
                const auto& x{subs[0].ss};
1111
88
                const auto& y{subs[1].ss};
1112
88
                return {x.Sat() + y.Sat() + SatInfo::BinaryOp(), x.Dsat() + y.Dsat() + SatInfo::BinaryOp()};
1113
12
            }
1114
0
            case Fragment::OR_B: {
1115
0
                const auto& x{subs[0].ss};
1116
0
                const auto& y{subs[1].ss};
1117
0
                return {
1118
0
                    ((x.Sat() + y.Dsat()) | (x.Dsat() + y.Sat())) + SatInfo::BinaryOp(),
1119
0
                    x.Dsat() + y.Dsat() + SatInfo::BinaryOp()
1120
0
                };
1121
12
            }
1122
0
            case Fragment::OR_C: {
1123
0
                const auto& x{subs[0].ss};
1124
0
                const auto& y{subs[1].ss};
1125
0
                return {(x.Sat() + SatInfo::If()) | (x.Dsat() + SatInfo::If() + y.Sat()), {}};
1126
12
            }
1127
0
            case Fragment::OR_D: {
1128
0
                const auto& x{subs[0].ss};
1129
0
                const auto& y{subs[1].ss};
1130
0
                return {
1131
0
                    (x.Sat() + SatInfo::OP_IFDUP(true) + SatInfo::If()) | (x.Dsat() + SatInfo::OP_IFDUP(false) + SatInfo::If() + y.Sat()),
1132
0
                    x.Dsat() + SatInfo::OP_IFDUP(false) + SatInfo::If() + y.Dsat()
1133
0
                };
1134
12
            }
1135
0
            case Fragment::OR_I: {
1136
0
                const auto& x{subs[0].ss};
1137
0
                const auto& y{subs[1].ss};
1138
0
                return {SatInfo::If() + (x.Sat() | y.Sat()), SatInfo::If() + (x.Dsat() | y.Dsat())};
1139
12
            }
1140
            // multi(k, key1, key2, ..., key_n) starts off with k+1 stack elements (a 0, plus k
1141
            // signatures), then reaches n+k+3 stack elements after pushing the n keys, plus k and
1142
            // n itself, and ends with 1 stack element (success or failure). Thus, it net removes
1143
            // k elements (from k+1 to 1), while reaching k+n+2 more than it ends with.
1144
0
            case Fragment::MULTI: return {SatInfo(k, k + keys.size() + 2)};
1145
            // multi_a(k, key1, key2, ..., key_n) starts off with n stack elements (the
1146
            // signatures), reaches 1 more (after the first key push), and ends with 1. Thus it net
1147
            // removes n-1 elements (from n to 1) while reaching n more than it ends with.
1148
772
            case Fragment::MULTI_A: return {SatInfo(keys.size() - 1, keys.size())};
1149
116
            case Fragment::WRAP_A:
1150
7.24M
            case Fragment::WRAP_N:
1151
7.24M
            case Fragment::WRAP_S: return subs[0].ss;
1152
2.58k
            case Fragment::WRAP_C: return {
1153
2.58k
                subs[0].ss.Sat() + SatInfo::OP_CHECKSIG(),
1154
2.58k
                subs[0].ss.Dsat() + SatInfo::OP_CHECKSIG()
1155
2.58k
            };
1156
6
            case Fragment::WRAP_D: return {
1157
6
                SatInfo::OP_DUP() + SatInfo::If() + subs[0].ss.Sat(),
1158
6
                SatInfo::OP_DUP() + SatInfo::If()
1159
6
            };
1160
558
            case Fragment::WRAP_V: return {subs[0].ss.Sat() + SatInfo::OP_VERIFY(), {}};
1161
0
            case Fragment::WRAP_J: return {
1162
0
                SatInfo::OP_SIZE() + SatInfo::OP_0NOTEQUAL() + SatInfo::If() + subs[0].ss.Sat(),
1163
0
                SatInfo::OP_SIZE() + SatInfo::OP_0NOTEQUAL() + SatInfo::If()
1164
0
            };
1165
28
            case Fragment::THRESH: {
1166
                // sats[j] is the SatInfo corresponding to all traces reaching j satisfactions.
1167
28
                auto sats = Vector(SatInfo::Empty());
1168
112
                for (size_t i = 0; i < subs.size(); ++i) {
1169
                    // Loop over the subexpressions, processing them one by one. After adding
1170
                    // element i we need to add OP_ADD (if i>0).
1171
84
                    auto add = i ? SatInfo::BinaryOp() : SatInfo::Empty();
1172
                    // Construct a variable that will become the next sats, starting with index 0.
1173
84
                    auto next_sats = Vector(sats[0] + subs[i].ss.Dsat() + add);
1174
                    // Then loop to construct next_sats[1..i].
1175
168
                    for (size_t j = 1; j < sats.size(); ++j) {
1176
84
                        next_sats.push_back(((sats[j] + subs[i].ss.Dsat()) | (sats[j - 1] + subs[i].ss.Sat())) + add);
1177
84
                    }
1178
                    // Finally construct next_sats[i+1].
1179
84
                    next_sats.push_back(sats[sats.size() - 1] + subs[i].ss.Sat() + add);
1180
                    // Switch over.
1181
84
                    sats = std::move(next_sats);
1182
84
                }
1183
                // To satisfy thresh we need k satisfactions; to dissatisfy we need 0. In both
1184
                // cases a push of k and an OP_EQUAL follow.
1185
28
                return {
1186
28
                    sats[k] + SatInfo::Push() + SatInfo::OP_EQUAL(),
1187
28
                    sats[0] + SatInfo::Push() + SatInfo::OP_EQUAL()
1188
28
                };
1189
7.24M
            }
1190
7.25M
        }
1191
7.25M
        assert(false);
1192
0
    }
1193
1194
9.01M
    internal::WitnessSize CalcWitnessSize() const {
1195
9.01M
        const uint32_t sig_size = IsTapscript(m_script_ctx) ? 1 + 65 : 1 + 72;
1196
9.01M
        const uint32_t pubkey_size = IsTapscript(m_script_ctx) ? 1 + 32 : 1 + 33;
1197
9.01M
        switch (fragment) {
1198
709
            case Fragment::JUST_0: return {{}, 0};
1199
245
            case Fragment::JUST_1:
1200
8.23k
            case Fragment::OLDER:
1201
9.38k
            case Fragment::AFTER: return {0, {}};
1202
5.50k
            case Fragment::PK_K: return {sig_size, 1};
1203
814
            case Fragment::PK_H: return {sig_size + pubkey_size, 1 + pubkey_size};
1204
110
            case Fragment::SHA256:
1205
187
            case Fragment::RIPEMD160:
1206
303
            case Fragment::HASH256:
1207
400
            case Fragment::HASH160: return {1 + 32, {}};
1208
260
            case Fragment::ANDOR: {
1209
260
                const auto sat{(subs[0].ws.sat + subs[1].ws.sat) | (subs[0].ws.dsat + subs[2].ws.sat)};
1210
260
                const auto dsat{subs[0].ws.dsat + subs[2].ws.dsat};
1211
260
                return {sat, dsat};
1212
303
            }
1213
1.56k
            case Fragment::AND_V: return {subs[0].ws.sat + subs[1].ws.sat, {}};
1214
7.19k
            case Fragment::AND_B: return {subs[0].ws.sat + subs[1].ws.sat, subs[0].ws.dsat + subs[1].ws.dsat};
1215
91
            case Fragment::OR_B: {
1216
91
                const auto sat{(subs[0].ws.dsat + subs[1].ws.sat) | (subs[0].ws.sat + subs[1].ws.dsat)};
1217
91
                const auto dsat{subs[0].ws.dsat + subs[1].ws.dsat};
1218
91
                return {sat, dsat};
1219
303
            }
1220
60
            case Fragment::OR_C: return {subs[0].ws.sat | (subs[0].ws.dsat + subs[1].ws.sat), {}};
1221
126
            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};
1222
645
            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)};
1223
173
            case Fragment::MULTI: return {k * sig_size + 1, k + 1};
1224
809
            case Fragment::MULTI_A: return {k * sig_size + static_cast<uint32_t>(keys.size()) - k, static_cast<uint32_t>(keys.size())};
1225
7.57k
            case Fragment::WRAP_A:
1226
8.97M
            case Fragment::WRAP_N:
1227
8.97M
            case Fragment::WRAP_S:
1228
8.98M
            case Fragment::WRAP_C: return subs[0].ws;
1229
122
            case Fragment::WRAP_D: return {1 + 1 + subs[0].ws.sat, 1};
1230
1.71k
            case Fragment::WRAP_V: return {subs[0].ws.sat, {}};
1231
16
            case Fragment::WRAP_J: return {subs[0].ws.sat, 1};
1232
410
            case Fragment::THRESH: {
1233
410
                auto sats = Vector(internal::MaxInt<uint32_t>(0));
1234
1.57k
                for (const auto& sub : subs) {
1235
1.57k
                    auto next_sats = Vector(sats[0] + sub.ws.dsat);
1236
4.64k
                    for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub.ws.dsat) | (sats[j - 1] + sub.ws.sat));
1237
1.57k
                    next_sats.push_back(sats[sats.size() - 1] + sub.ws.sat);
1238
1.57k
                    sats = std::move(next_sats);
1239
1.57k
                }
1240
410
                assert(k < sats.size());
1241
410
                return {sats[k], sats[0]};
1242
410
            }
1243
9.01M
        }
1244
9.01M
        assert(false);
1245
0
    }
miniscript::Node<CPubKey>::CalcWitnessSize() const
Line
Count
Source
1194
28.5k
    internal::WitnessSize CalcWitnessSize() const {
1195
28.5k
        const uint32_t sig_size = IsTapscript(m_script_ctx) ? 1 + 65 : 1 + 72;
1196
28.5k
        const uint32_t pubkey_size = IsTapscript(m_script_ctx) ? 1 + 32 : 1 + 33;
1197
28.5k
        switch (fragment) {
1198
449
            case Fragment::JUST_0: return {{}, 0};
1199
232
            case Fragment::JUST_1:
1200
7.83k
            case Fragment::OLDER:
1201
8.22k
            case Fragment::AFTER: return {0, {}};
1202
1.69k
            case Fragment::PK_K: return {sig_size, 1};
1203
115
            case Fragment::PK_H: return {sig_size + pubkey_size, 1 + pubkey_size};
1204
68
            case Fragment::SHA256:
1205
94
            case Fragment::RIPEMD160:
1206
134
            case Fragment::HASH256:
1207
158
            case Fragment::HASH160: return {1 + 32, {}};
1208
124
            case Fragment::ANDOR: {
1209
124
                const auto sat{(subs[0].ws.sat + subs[1].ws.sat) | (subs[0].ws.dsat + subs[2].ws.sat)};
1210
124
                const auto dsat{subs[0].ws.dsat + subs[2].ws.dsat};
1211
124
                return {sat, dsat};
1212
134
            }
1213
292
            case Fragment::AND_V: return {subs[0].ws.sat + subs[1].ws.sat, {}};
1214
6.85k
            case Fragment::AND_B: return {subs[0].ws.sat + subs[1].ws.sat, subs[0].ws.dsat + subs[1].ws.dsat};
1215
29
            case Fragment::OR_B: {
1216
29
                const auto sat{(subs[0].ws.dsat + subs[1].ws.sat) | (subs[0].ws.sat + subs[1].ws.dsat)};
1217
29
                const auto dsat{subs[0].ws.dsat + subs[1].ws.dsat};
1218
29
                return {sat, dsat};
1219
134
            }
1220
20
            case Fragment::OR_C: return {subs[0].ws.sat | (subs[0].ws.dsat + subs[1].ws.sat), {}};
1221
42
            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};
1222
391
            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)};
1223
49
            case Fragment::MULTI: return {k * sig_size + 1, k + 1};
1224
5
            case Fragment::MULTI_A: return {k * sig_size + static_cast<uint32_t>(keys.size()) - k, static_cast<uint32_t>(keys.size())};
1225
6.96k
            case Fragment::WRAP_A:
1226
7.27k
            case Fragment::WRAP_N:
1227
7.74k
            case Fragment::WRAP_S:
1228
9.51k
            case Fragment::WRAP_C: return subs[0].ws;
1229
44
            case Fragment::WRAP_D: return {1 + 1 + subs[0].ws.sat, 1};
1230
356
            case Fragment::WRAP_V: return {subs[0].ws.sat, {}};
1231
16
            case Fragment::WRAP_J: return {subs[0].ws.sat, 1};
1232
140
            case Fragment::THRESH: {
1233
140
                auto sats = Vector(internal::MaxInt<uint32_t>(0));
1234
679
                for (const auto& sub : subs) {
1235
679
                    auto next_sats = Vector(sats[0] + sub.ws.dsat);
1236
2.35k
                    for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub.ws.dsat) | (sats[j - 1] + sub.ws.sat));
1237
679
                    next_sats.push_back(sats[sats.size() - 1] + sub.ws.sat);
1238
679
                    sats = std::move(next_sats);
1239
679
                }
1240
140
                assert(k < sats.size());
1241
140
                return {sats[k], sats[0]};
1242
140
            }
1243
28.5k
        }
1244
28.5k
        assert(false);
1245
0
    }
miniscript::Node<unsigned int>::CalcWitnessSize() const
Line
Count
Source
1194
1.72M
    internal::WitnessSize CalcWitnessSize() const {
1195
1.72M
        const uint32_t sig_size = IsTapscript(m_script_ctx) ? 1 + 65 : 1 + 72;
1196
1.72M
        const uint32_t pubkey_size = IsTapscript(m_script_ctx) ? 1 + 32 : 1 + 33;
1197
1.72M
        switch (fragment) {
1198
260
            case Fragment::JUST_0: return {{}, 0};
1199
13
            case Fragment::JUST_1:
1200
335
            case Fragment::OLDER:
1201
674
            case Fragment::AFTER: return {0, {}};
1202
1.44k
            case Fragment::PK_K: return {sig_size, 1};
1203
475
            case Fragment::PK_H: return {sig_size + pubkey_size, 1 + pubkey_size};
1204
42
            case Fragment::SHA256:
1205
93
            case Fragment::RIPEMD160:
1206
157
            case Fragment::HASH256:
1207
230
            case Fragment::HASH160: return {1 + 32, {}};
1208
136
            case Fragment::ANDOR: {
1209
136
                const auto sat{(subs[0].ws.sat + subs[1].ws.sat) | (subs[0].ws.dsat + subs[2].ws.sat)};
1210
136
                const auto dsat{subs[0].ws.dsat + subs[2].ws.dsat};
1211
136
                return {sat, dsat};
1212
157
            }
1213
724
            case Fragment::AND_V: return {subs[0].ws.sat + subs[1].ws.sat, {}};
1214
249
            case Fragment::AND_B: return {subs[0].ws.sat + subs[1].ws.sat, subs[0].ws.dsat + subs[1].ws.dsat};
1215
62
            case Fragment::OR_B: {
1216
62
                const auto sat{(subs[0].ws.dsat + subs[1].ws.sat) | (subs[0].ws.sat + subs[1].ws.dsat)};
1217
62
                const auto dsat{subs[0].ws.dsat + subs[1].ws.dsat};
1218
62
                return {sat, dsat};
1219
157
            }
1220
40
            case Fragment::OR_C: return {subs[0].ws.sat | (subs[0].ws.dsat + subs[1].ws.sat), {}};
1221
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};
1222
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)};
1223
124
            case Fragment::MULTI: return {k * sig_size + 1, k + 1};
1224
32
            case Fragment::MULTI_A: return {k * sig_size + static_cast<uint32_t>(keys.size()) - k, static_cast<uint32_t>(keys.size())};
1225
495
            case Fragment::WRAP_A:
1226
1.71M
            case Fragment::WRAP_N:
1227
1.71M
            case Fragment::WRAP_S:
1228
1.72M
            case Fragment::WRAP_C: return subs[0].ws;
1229
72
            case Fragment::WRAP_D: return {1 + 1 + subs[0].ws.sat, 1};
1230
801
            case Fragment::WRAP_V: return {subs[0].ws.sat, {}};
1231
0
            case Fragment::WRAP_J: return {subs[0].ws.sat, 1};
1232
242
            case Fragment::THRESH: {
1233
242
                auto sats = Vector(internal::MaxInt<uint32_t>(0));
1234
814
                for (const auto& sub : subs) {
1235
814
                    auto next_sats = Vector(sats[0] + sub.ws.dsat);
1236
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));
1237
814
                    next_sats.push_back(sats[sats.size() - 1] + sub.ws.sat);
1238
814
                    sats = std::move(next_sats);
1239
814
                }
1240
242
                assert(k < sats.size());
1241
242
                return {sats[k], sats[0]};
1242
242
            }
1243
1.72M
        }
1244
1.72M
        assert(false);
1245
0
    }
miniscript::Node<XOnlyPubKey>::CalcWitnessSize() const
Line
Count
Source
1194
7.25M
    internal::WitnessSize CalcWitnessSize() const {
1195
7.25M
        const uint32_t sig_size = IsTapscript(m_script_ctx) ? 1 + 65 : 1 + 72;
1196
7.25M
        const uint32_t pubkey_size = IsTapscript(m_script_ctx) ? 1 + 32 : 1 + 33;
1197
7.25M
        switch (fragment) {
1198
0
            case Fragment::JUST_0: return {{}, 0};
1199
0
            case Fragment::JUST_1:
1200
60
            case Fragment::OLDER:
1201
488
            case Fragment::AFTER: return {0, {}};
1202
2.36k
            case Fragment::PK_K: return {sig_size, 1};
1203
224
            case Fragment::PK_H: return {sig_size + pubkey_size, 1 + pubkey_size};
1204
0
            case Fragment::SHA256:
1205
0
            case Fragment::RIPEMD160:
1206
12
            case Fragment::HASH256:
1207
12
            case Fragment::HASH160: return {1 + 32, {}};
1208
0
            case Fragment::ANDOR: {
1209
0
                const auto sat{(subs[0].ws.sat + subs[1].ws.sat) | (subs[0].ws.dsat + subs[2].ws.sat)};
1210
0
                const auto dsat{subs[0].ws.dsat + subs[2].ws.dsat};
1211
0
                return {sat, dsat};
1212
12
            }
1213
552
            case Fragment::AND_V: return {subs[0].ws.sat + subs[1].ws.sat, {}};
1214
88
            case Fragment::AND_B: return {subs[0].ws.sat + subs[1].ws.sat, subs[0].ws.dsat + subs[1].ws.dsat};
1215
0
            case Fragment::OR_B: {
1216
0
                const auto sat{(subs[0].ws.dsat + subs[1].ws.sat) | (subs[0].ws.sat + subs[1].ws.dsat)};
1217
0
                const auto dsat{subs[0].ws.dsat + subs[1].ws.dsat};
1218
0
                return {sat, dsat};
1219
12
            }
1220
0
            case Fragment::OR_C: return {subs[0].ws.sat | (subs[0].ws.dsat + subs[1].ws.sat), {}};
1221
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};
1222
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)};
1223
0
            case Fragment::MULTI: return {k * sig_size + 1, k + 1};
1224
772
            case Fragment::MULTI_A: return {k * sig_size + static_cast<uint32_t>(keys.size()) - k, static_cast<uint32_t>(keys.size())};
1225
116
            case Fragment::WRAP_A:
1226
7.24M
            case Fragment::WRAP_N:
1227
7.24M
            case Fragment::WRAP_S:
1228
7.25M
            case Fragment::WRAP_C: return subs[0].ws;
1229
6
            case Fragment::WRAP_D: return {1 + 1 + subs[0].ws.sat, 1};
1230
558
            case Fragment::WRAP_V: return {subs[0].ws.sat, {}};
1231
0
            case Fragment::WRAP_J: return {subs[0].ws.sat, 1};
1232
28
            case Fragment::THRESH: {
1233
28
                auto sats = Vector(internal::MaxInt<uint32_t>(0));
1234
84
                for (const auto& sub : subs) {
1235
84
                    auto next_sats = Vector(sats[0] + sub.ws.dsat);
1236
168
                    for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub.ws.dsat) | (sats[j - 1] + sub.ws.sat));
1237
84
                    next_sats.push_back(sats[sats.size() - 1] + sub.ws.sat);
1238
84
                    sats = std::move(next_sats);
1239
84
                }
1240
28
                assert(k < sats.size());
1241
28
                return {sats[k], sats[0]};
1242
28
            }
1243
7.25M
        }
1244
7.25M
        assert(false);
1245
0
    }
1246
1247
    template<typename Ctx>
1248
8.22k
    internal::InputResult ProduceInput(const Ctx& ctx) const {
1249
8.22k
        using namespace internal;
1250
1251
        // Internal function which is invoked for every tree node, constructing satisfaction/dissatisfactions
1252
        // given those of its subnodes.
1253
8.87M
        auto helper = [&ctx](const Node& node, std::span<InputResult> subres) -> InputResult {
1254
8.87M
            switch (node.fragment) {
1255
377k
                case Fragment::PK_K: {
1256
377k
                    std::vector<unsigned char> sig;
1257
377k
                    Availability avail = ctx.Sign(node.keys[0], sig);
1258
377k
                    return {ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
1259
0
                }
1260
993
                case Fragment::PK_H: {
1261
993
                    std::vector<unsigned char> key = ctx.ToPKBytes(node.keys[0]), sig;
1262
993
                    Availability avail = ctx.Sign(node.keys[0], sig);
1263
993
                    return {ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
1264
0
                }
1265
928
                case Fragment::MULTI_A: {
1266
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1267
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1268
928
                    std::vector<InputStack> sats = Vector(EMPTY);
1269
94.2k
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1270
                        // Get the signature for the i'th key in reverse order (the signature for the first key needs to
1271
                        // be at the top of the stack, contrary to CHECKMULTISIG's satisfaction).
1272
93.3k
                        std::vector<unsigned char> sig;
1273
93.3k
                        Availability avail = ctx.Sign(node.keys[node.keys.size() - 1 - i], sig);
1274
                        // Compute signature stack for just this key.
1275
93.3k
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1276
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1277
                        // next_sats[j] are equal to either the existing sats[j] + ZERO, or sats[j-1] plus a signature
1278
                        // for the current (i'th) key. The very last element needs all signatures filled.
1279
93.3k
                        std::vector<InputStack> next_sats;
1280
93.3k
                        next_sats.push_back(sats[0] + ZERO);
1281
44.4M
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + ZERO) | (std::move(sats[j - 1]) + sat));
1282
93.3k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1283
                        // Switch over.
1284
93.3k
                        sats = std::move(next_sats);
1285
93.3k
                    }
1286
                    // The dissatisfaction consists of as many empty vectors as there are keys, which is the same as
1287
                    // satisfying 0 keys.
1288
928
                    auto& nsat{sats[0]};
1289
928
                    CHECK_NONFATAL(node.k != 0);
1290
928
                    assert(node.k < sats.size());
1291
928
                    return {std::move(nsat), std::move(sats[node.k])};
1292
928
                }
1293
384
                case Fragment::MULTI: {
1294
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1295
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1296
                    // sats[0] starts off being {0}, due to the CHECKMULTISIG bug that pops off one element too many.
1297
384
                    std::vector<InputStack> sats = Vector(ZERO);
1298
1.14k
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1299
756
                        std::vector<unsigned char> sig;
1300
756
                        Availability avail = ctx.Sign(node.keys[i], sig);
1301
                        // Compute signature stack for just the i'th key.
1302
756
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1303
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1304
                        // next_sats[j] are equal to either the existing sats[j], or sats[j-1] plus a signature for the
1305
                        // current (i'th) key. The very last element needs all signatures filled.
1306
756
                        std::vector<InputStack> next_sats;
1307
756
                        next_sats.push_back(sats[0]);
1308
1.20k
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
1309
756
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1310
                        // Switch over.
1311
756
                        sats = std::move(next_sats);
1312
756
                    }
1313
                    // The dissatisfaction consists of k+1 stack elements all equal to 0.
1314
384
                    InputStack nsat = ZERO;
1315
1.11k
                    for (size_t i = 0; i < node.k; ++i) nsat = std::move(nsat) + ZERO;
1316
384
                    assert(node.k < sats.size());
1317
384
                    return {std::move(nsat), std::move(sats[node.k])};
1318
384
                }
1319
505
                case Fragment::THRESH: {
1320
                    // sats[k] represents the best stack that satisfies k out of the *last* i subexpressions.
1321
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1322
                    // sats[0] starts off empty.
1323
505
                    std::vector<InputStack> sats = Vector(EMPTY);
1324
2.27k
                    for (size_t i = 0; i < subres.size(); ++i) {
1325
                        // Introduce an alias for the i'th last satisfaction/dissatisfaction.
1326
1.76k
                        auto& res = subres[subres.size() - i - 1];
1327
                        // Compute the next sats vector: next_sats[0] is sats[0] plus res.nsat (thus containing all dissatisfactions
1328
                        // so far. next_sats[j] is either sats[j] + res.nsat (reusing j earlier satisfactions) or sats[j-1] + res.sat
1329
                        // (reusing j-1 earlier satisfactions plus a new one). The very last next_sats[j] is all satisfactions.
1330
1.76k
                        std::vector<InputStack> next_sats;
1331
1.76k
                        next_sats.push_back(sats[0] + res.nsat);
1332
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));
1333
1.76k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
1334
                        // Switch over.
1335
1.76k
                        sats = std::move(next_sats);
1336
1.76k
                    }
1337
                    // At this point, sats[k].sat is the best satisfaction for the overall thresh() node. The best dissatisfaction
1338
                    // is computed by gathering all sats[i].nsat for i != k.
1339
505
                    InputStack nsat = INVALID;
1340
2.77k
                    for (size_t i = 0; i < sats.size(); ++i) {
1341
                        // i==k is the satisfaction; i==0 is the canonical dissatisfaction;
1342
                        // the rest are non-canonical (a no-signature dissatisfaction - the i=0
1343
                        // form - is always available) and malleable (due to overcompleteness).
1344
                        // Marking the solutions malleable here is not strictly necessary, as they
1345
                        // should already never be picked in non-malleable solutions due to the
1346
                        // availability of the i=0 form.
1347
2.27k
                        if (i != 0 && i != node.k) sats[i].SetMalleable().SetNonCanon();
1348
                        // Include all dissatisfactions (even these non-canonical ones) in nsat.
1349
2.27k
                        if (i != node.k) nsat = std::move(nsat) | std::move(sats[i]);
1350
2.27k
                    }
1351
505
                    assert(node.k < sats.size());
1352
505
                    return {std::move(nsat), std::move(sats[node.k])};
1353
505
                }
1354
37.0k
                case Fragment::OLDER: {
1355
37.0k
                    return {INVALID, ctx.CheckOlder(node.k) ? EMPTY : INVALID};
1356
505
                }
1357
1.98k
                case Fragment::AFTER: {
1358
1.98k
                    return {INVALID, ctx.CheckAfter(node.k) ? EMPTY : INVALID};
1359
505
                }
1360
529
                case Fragment::SHA256: {
1361
529
                    std::vector<unsigned char> preimage;
1362
529
                    Availability avail = ctx.SatSHA256(node.data, preimage);
1363
529
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1364
505
                }
1365
222
                case Fragment::RIPEMD160: {
1366
222
                    std::vector<unsigned char> preimage;
1367
222
                    Availability avail = ctx.SatRIPEMD160(node.data, preimage);
1368
222
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1369
505
                }
1370
396
                case Fragment::HASH256: {
1371
396
                    std::vector<unsigned char> preimage;
1372
396
                    Availability avail = ctx.SatHASH256(node.data, preimage);
1373
396
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1374
505
                }
1375
168
                case Fragment::HASH160: {
1376
168
                    std::vector<unsigned char> preimage;
1377
168
                    Availability avail = ctx.SatHASH160(node.data, preimage);
1378
168
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1379
505
                }
1380
2.02k
                case Fragment::AND_V: {
1381
2.02k
                    auto& x = subres[0], &y = subres[1];
1382
                    // As the dissatisfaction here only consist of a single option, it doesn't
1383
                    // actually need to be listed (it's not required for reasoning about malleability of
1384
                    // other options), and is never required (no valid miniscript relies on the ability
1385
                    // to satisfy the type V left subexpression). It's still listed here for
1386
                    // completeness, as a hypothetical (not currently implemented) satisfier that doesn't
1387
                    // care about malleability might in some cases prefer it still.
1388
2.02k
                    return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
1389
505
                }
1390
407k
                case Fragment::AND_B: {
1391
407k
                    auto& x = subres[0], &y = subres[1];
1392
                    // Note that it is not strictly necessary to mark the 2nd and 3rd dissatisfaction here
1393
                    // as malleable. While they are definitely malleable, they are also non-canonical due
1394
                    // to the guaranteed existence of a no-signature other dissatisfaction (the 1st)
1395
                    // option. Because of that, the 2nd and 3rd option will never be chosen, even if they
1396
                    // weren't marked as malleable.
1397
407k
                    return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
1398
505
                }
1399
144
                case Fragment::OR_B: {
1400
144
                    auto& x = subres[0], &z = subres[1];
1401
                    // The (sat(Z) sat(X)) solution is overcomplete (attacker can change either into dsat).
1402
144
                    return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
1403
505
                }
1404
90
                case Fragment::OR_C: {
1405
90
                    auto& x = subres[0], &z = subres[1];
1406
90
                    return {INVALID, std::move(x.sat) | (z.sat + x.nsat)};
1407
505
                }
1408
316
                case Fragment::OR_D: {
1409
316
                    auto& x = subres[0], &z = subres[1];
1410
316
                    return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
1411
505
                }
1412
1.81k
                case Fragment::OR_I: {
1413
1.81k
                    auto& x = subres[0], &z = subres[1];
1414
1.81k
                    return {(x.nsat + ONE) | (z.nsat + ZERO), (x.sat + ONE) | (z.sat + ZERO)};
1415
505
                }
1416
730
                case Fragment::ANDOR: {
1417
730
                    auto& x = subres[0], &y = subres[1], &z = subres[2];
1418
730
                    return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
1419
505
                }
1420
408k
                case Fragment::WRAP_A:
1421
409k
                case Fragment::WRAP_S:
1422
787k
                case Fragment::WRAP_C:
1423
8.03M
                case Fragment::WRAP_N:
1424
8.03M
                    return std::move(subres[0]);
1425
133
                case Fragment::WRAP_D: {
1426
133
                    auto &x = subres[0];
1427
133
                    return {ZERO, x.sat + ONE};
1428
787k
                }
1429
198
                case Fragment::WRAP_J: {
1430
198
                    auto &x = subres[0];
1431
                    // If a dissatisfaction with a nonzero top stack element exists, an alternative dissatisfaction exists.
1432
                    // As the dissatisfaction logic currently doesn't keep track of this nonzeroness property, and thus even
1433
                    // if a dissatisfaction with a top zero element is found, we don't know whether another one with a
1434
                    // nonzero top stack element exists. Make the conservative assumption that whenever the subexpression is weakly
1435
                    // dissatisfiable, this alternative dissatisfaction exists and leads to malleability.
1436
198
                    return {InputStack(ZERO).SetMalleable(x.nsat.available != Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
1437
787k
                }
1438
2.36k
                case Fragment::WRAP_V: {
1439
2.36k
                    auto &x = subres[0];
1440
2.36k
                    return {INVALID, std::move(x.sat)};
1441
787k
                }
1442
1.74k
                case Fragment::JUST_0: return {EMPTY, INVALID};
1443
972
                case Fragment::JUST_1: return {INVALID, EMPTY};
1444
8.87M
            }
1445
8.87M
            assert(false);
1446
0
            return {INVALID, INVALID};
1447
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
1253
1.61M
        auto helper = [&ctx](const Node& node, std::span<InputResult> subres) -> InputResult {
1254
1.61M
            switch (node.fragment) {
1255
374k
                case Fragment::PK_K: {
1256
374k
                    std::vector<unsigned char> sig;
1257
374k
                    Availability avail = ctx.Sign(node.keys[0], sig);
1258
374k
                    return {ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
1259
0
                }
1260
708
                case Fragment::PK_H: {
1261
708
                    std::vector<unsigned char> key = ctx.ToPKBytes(node.keys[0]), sig;
1262
708
                    Availability avail = ctx.Sign(node.keys[0], sig);
1263
708
                    return {ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
1264
0
                }
1265
156
                case Fragment::MULTI_A: {
1266
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1267
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1268
156
                    std::vector<InputStack> sats = Vector(EMPTY);
1269
2.97k
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1270
                        // Get the signature for the i'th key in reverse order (the signature for the first key needs to
1271
                        // be at the top of the stack, contrary to CHECKMULTISIG's satisfaction).
1272
2.82k
                        std::vector<unsigned char> sig;
1273
2.82k
                        Availability avail = ctx.Sign(node.keys[node.keys.size() - 1 - i], sig);
1274
                        // Compute signature stack for just this key.
1275
2.82k
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1276
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1277
                        // next_sats[j] are equal to either the existing sats[j] + ZERO, or sats[j-1] plus a signature
1278
                        // for the current (i'th) key. The very last element needs all signatures filled.
1279
2.82k
                        std::vector<InputStack> next_sats;
1280
2.82k
                        next_sats.push_back(sats[0] + ZERO);
1281
30.5k
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + ZERO) | (std::move(sats[j - 1]) + sat));
1282
2.82k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1283
                        // Switch over.
1284
2.82k
                        sats = std::move(next_sats);
1285
2.82k
                    }
1286
                    // The dissatisfaction consists of as many empty vectors as there are keys, which is the same as
1287
                    // satisfying 0 keys.
1288
156
                    auto& nsat{sats[0]};
1289
156
                    CHECK_NONFATAL(node.k != 0);
1290
156
                    assert(node.k < sats.size());
1291
156
                    return {std::move(nsat), std::move(sats[node.k])};
1292
156
                }
1293
360
                case Fragment::MULTI: {
1294
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1295
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1296
                    // sats[0] starts off being {0}, due to the CHECKMULTISIG bug that pops off one element too many.
1297
360
                    std::vector<InputStack> sats = Vector(ZERO);
1298
1.06k
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1299
708
                        std::vector<unsigned char> sig;
1300
708
                        Availability avail = ctx.Sign(node.keys[i], sig);
1301
                        // Compute signature stack for just the i'th key.
1302
708
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1303
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1304
                        // next_sats[j] are equal to either the existing sats[j], or sats[j-1] plus a signature for the
1305
                        // current (i'th) key. The very last element needs all signatures filled.
1306
708
                        std::vector<InputStack> next_sats;
1307
708
                        next_sats.push_back(sats[0]);
1308
1.12k
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
1309
708
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1310
                        // Switch over.
1311
708
                        sats = std::move(next_sats);
1312
708
                    }
1313
                    // The dissatisfaction consists of k+1 stack elements all equal to 0.
1314
360
                    InputStack nsat = ZERO;
1315
1.06k
                    for (size_t i = 0; i < node.k; ++i) nsat = std::move(nsat) + ZERO;
1316
360
                    assert(node.k < sats.size());
1317
360
                    return {std::move(nsat), std::move(sats[node.k])};
1318
360
                }
1319
372
                case Fragment::THRESH: {
1320
                    // sats[k] represents the best stack that satisfies k out of the *last* i subexpressions.
1321
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1322
                    // sats[0] starts off empty.
1323
372
                    std::vector<InputStack> sats = Vector(EMPTY);
1324
1.47k
                    for (size_t i = 0; i < subres.size(); ++i) {
1325
                        // Introduce an alias for the i'th last satisfaction/dissatisfaction.
1326
1.10k
                        auto& res = subres[subres.size() - i - 1];
1327
                        // Compute the next sats vector: next_sats[0] is sats[0] plus res.nsat (thus containing all dissatisfactions
1328
                        // so far. next_sats[j] is either sats[j] + res.nsat (reusing j earlier satisfactions) or sats[j-1] + res.sat
1329
                        // (reusing j-1 earlier satisfactions plus a new one). The very last next_sats[j] is all satisfactions.
1330
1.10k
                        std::vector<InputStack> next_sats;
1331
1.10k
                        next_sats.push_back(sats[0] + res.nsat);
1332
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));
1333
1.10k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
1334
                        // Switch over.
1335
1.10k
                        sats = std::move(next_sats);
1336
1.10k
                    }
1337
                    // At this point, sats[k].sat is the best satisfaction for the overall thresh() node. The best dissatisfaction
1338
                    // is computed by gathering all sats[i].nsat for i != k.
1339
372
                    InputStack nsat = INVALID;
1340
1.84k
                    for (size_t i = 0; i < sats.size(); ++i) {
1341
                        // i==k is the satisfaction; i==0 is the canonical dissatisfaction;
1342
                        // the rest are non-canonical (a no-signature dissatisfaction - the i=0
1343
                        // form - is always available) and malleable (due to overcompleteness).
1344
                        // Marking the solutions malleable here is not strictly necessary, as they
1345
                        // should already never be picked in non-malleable solutions due to the
1346
                        // availability of the i=0 form.
1347
1.47k
                        if (i != 0 && i != node.k) sats[i].SetMalleable().SetNonCanon();
1348
                        // Include all dissatisfactions (even these non-canonical ones) in nsat.
1349
1.47k
                        if (i != node.k) nsat = std::move(nsat) | std::move(sats[i]);
1350
1.47k
                    }
1351
372
                    assert(node.k < sats.size());
1352
372
                    return {std::move(nsat), std::move(sats[node.k])};
1353
372
                }
1354
36.9k
                case Fragment::OLDER: {
1355
36.9k
                    return {INVALID, ctx.CheckOlder(node.k) ? EMPTY : INVALID};
1356
372
                }
1357
1.30k
                case Fragment::AFTER: {
1358
1.30k
                    return {INVALID, ctx.CheckAfter(node.k) ? EMPTY : INVALID};
1359
372
                }
1360
504
                case Fragment::SHA256: {
1361
504
                    std::vector<unsigned char> preimage;
1362
504
                    Availability avail = ctx.SatSHA256(node.data, preimage);
1363
504
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1364
372
                }
1365
210
                case Fragment::RIPEMD160: {
1366
210
                    std::vector<unsigned char> preimage;
1367
210
                    Availability avail = ctx.SatRIPEMD160(node.data, preimage);
1368
210
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1369
372
                }
1370
372
                case Fragment::HASH256: {
1371
372
                    std::vector<unsigned char> preimage;
1372
372
                    Availability avail = ctx.SatHASH256(node.data, preimage);
1373
372
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1374
372
                }
1375
156
                case Fragment::HASH160: {
1376
156
                    std::vector<unsigned char> preimage;
1377
156
                    Availability avail = ctx.SatHASH160(node.data, preimage);
1378
156
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1379
372
                }
1380
1.32k
                case Fragment::AND_V: {
1381
1.32k
                    auto& x = subres[0], &y = subres[1];
1382
                    // As the dissatisfaction here only consist of a single option, it doesn't
1383
                    // actually need to be listed (it's not required for reasoning about malleability of
1384
                    // other options), and is never required (no valid miniscript relies on the ability
1385
                    // to satisfy the type V left subexpression). It's still listed here for
1386
                    // completeness, as a hypothetical (not currently implemented) satisfier that doesn't
1387
                    // care about malleability might in some cases prefer it still.
1388
1.32k
                    return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
1389
372
                }
1390
407k
                case Fragment::AND_B: {
1391
407k
                    auto& x = subres[0], &y = subres[1];
1392
                    // Note that it is not strictly necessary to mark the 2nd and 3rd dissatisfaction here
1393
                    // as malleable. While they are definitely malleable, they are also non-canonical due
1394
                    // to the guaranteed existence of a no-signature other dissatisfaction (the 1st)
1395
                    // option. Because of that, the 2nd and 3rd option will never be chosen, even if they
1396
                    // weren't marked as malleable.
1397
407k
                    return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
1398
372
                }
1399
144
                case Fragment::OR_B: {
1400
144
                    auto& x = subres[0], &z = subres[1];
1401
                    // The (sat(Z) sat(X)) solution is overcomplete (attacker can change either into dsat).
1402
144
                    return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
1403
372
                }
1404
90
                case Fragment::OR_C: {
1405
90
                    auto& x = subres[0], &z = subres[1];
1406
90
                    return {INVALID, std::move(x.sat) | (z.sat + x.nsat)};
1407
372
                }
1408
312
                case Fragment::OR_D: {
1409
312
                    auto& x = subres[0], &z = subres[1];
1410
312
                    return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
1411
372
                }
1412
1.59k
                case Fragment::OR_I: {
1413
1.59k
                    auto& x = subres[0], &z = subres[1];
1414
1.59k
                    return {(x.nsat + ONE) | (z.nsat + ZERO), (x.sat + ONE) | (z.sat + ZERO)};
1415
372
                }
1416
672
                case Fragment::ANDOR: {
1417
672
                    auto& x = subres[0], &y = subres[1], &z = subres[2];
1418
672
                    return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
1419
372
                }
1420
408k
                case Fragment::WRAP_A:
1421
408k
                case Fragment::WRAP_S:
1422
783k
                case Fragment::WRAP_C:
1423
783k
                case Fragment::WRAP_N:
1424
783k
                    return std::move(subres[0]);
1425
96
                case Fragment::WRAP_D: {
1426
96
                    auto &x = subres[0];
1427
96
                    return {ZERO, x.sat + ONE};
1428
783k
                }
1429
198
                case Fragment::WRAP_J: {
1430
198
                    auto &x = subres[0];
1431
                    // If a dissatisfaction with a nonzero top stack element exists, an alternative dissatisfaction exists.
1432
                    // As the dissatisfaction logic currently doesn't keep track of this nonzeroness property, and thus even
1433
                    // if a dissatisfaction with a top zero element is found, we don't know whether another one with a
1434
                    // nonzero top stack element exists. Make the conservative assumption that whenever the subexpression is weakly
1435
                    // dissatisfiable, this alternative dissatisfaction exists and leads to malleability.
1436
198
                    return {InputStack(ZERO).SetMalleable(x.nsat.available != Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
1437
783k
                }
1438
1.62k
                case Fragment::WRAP_V: {
1439
1.62k
                    auto &x = subres[0];
1440
1.62k
                    return {INVALID, std::move(x.sat)};
1441
783k
                }
1442
1.50k
                case Fragment::JUST_0: return {EMPTY, INVALID};
1443
972
                case Fragment::JUST_1: return {INVALID, EMPTY};
1444
1.61M
            }
1445
1.61M
            assert(false);
1446
0
            return {INVALID, INVALID};
1447
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
1253
7.25M
        auto helper = [&ctx](const Node& node, std::span<InputResult> subres) -> InputResult {
1254
7.25M
            switch (node.fragment) {
1255
2.36k
                case Fragment::PK_K: {
1256
2.36k
                    std::vector<unsigned char> sig;
1257
2.36k
                    Availability avail = ctx.Sign(node.keys[0], sig);
1258
2.36k
                    return {ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
1259
0
                }
1260
224
                case Fragment::PK_H: {
1261
224
                    std::vector<unsigned char> key = ctx.ToPKBytes(node.keys[0]), sig;
1262
224
                    Availability avail = ctx.Sign(node.keys[0], sig);
1263
224
                    return {ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
1264
0
                }
1265
772
                case Fragment::MULTI_A: {
1266
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1267
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1268
772
                    std::vector<InputStack> sats = Vector(EMPTY);
1269
91.2k
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1270
                        // Get the signature for the i'th key in reverse order (the signature for the first key needs to
1271
                        // be at the top of the stack, contrary to CHECKMULTISIG's satisfaction).
1272
90.5k
                        std::vector<unsigned char> sig;
1273
90.5k
                        Availability avail = ctx.Sign(node.keys[node.keys.size() - 1 - i], sig);
1274
                        // Compute signature stack for just this key.
1275
90.5k
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1276
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1277
                        // next_sats[j] are equal to either the existing sats[j] + ZERO, or sats[j-1] plus a signature
1278
                        // for the current (i'th) key. The very last element needs all signatures filled.
1279
90.5k
                        std::vector<InputStack> next_sats;
1280
90.5k
                        next_sats.push_back(sats[0] + ZERO);
1281
44.4M
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + ZERO) | (std::move(sats[j - 1]) + sat));
1282
90.5k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1283
                        // Switch over.
1284
90.5k
                        sats = std::move(next_sats);
1285
90.5k
                    }
1286
                    // The dissatisfaction consists of as many empty vectors as there are keys, which is the same as
1287
                    // satisfying 0 keys.
1288
772
                    auto& nsat{sats[0]};
1289
772
                    CHECK_NONFATAL(node.k != 0);
1290
772
                    assert(node.k < sats.size());
1291
772
                    return {std::move(nsat), std::move(sats[node.k])};
1292
772
                }
1293
0
                case Fragment::MULTI: {
1294
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1295
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1296
                    // sats[0] starts off being {0}, due to the CHECKMULTISIG bug that pops off one element too many.
1297
0
                    std::vector<InputStack> sats = Vector(ZERO);
1298
0
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1299
0
                        std::vector<unsigned char> sig;
1300
0
                        Availability avail = ctx.Sign(node.keys[i], sig);
1301
                        // Compute signature stack for just the i'th key.
1302
0
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1303
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1304
                        // next_sats[j] are equal to either the existing sats[j], or sats[j-1] plus a signature for the
1305
                        // current (i'th) key. The very last element needs all signatures filled.
1306
0
                        std::vector<InputStack> next_sats;
1307
0
                        next_sats.push_back(sats[0]);
1308
0
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
1309
0
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1310
                        // Switch over.
1311
0
                        sats = std::move(next_sats);
1312
0
                    }
1313
                    // The dissatisfaction consists of k+1 stack elements all equal to 0.
1314
0
                    InputStack nsat = ZERO;
1315
0
                    for (size_t i = 0; i < node.k; ++i) nsat = std::move(nsat) + ZERO;
1316
0
                    assert(node.k < sats.size());
1317
0
                    return {std::move(nsat), std::move(sats[node.k])};
1318
0
                }
1319
28
                case Fragment::THRESH: {
1320
                    // sats[k] represents the best stack that satisfies k out of the *last* i subexpressions.
1321
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1322
                    // sats[0] starts off empty.
1323
28
                    std::vector<InputStack> sats = Vector(EMPTY);
1324
112
                    for (size_t i = 0; i < subres.size(); ++i) {
1325
                        // Introduce an alias for the i'th last satisfaction/dissatisfaction.
1326
84
                        auto& res = subres[subres.size() - i - 1];
1327
                        // Compute the next sats vector: next_sats[0] is sats[0] plus res.nsat (thus containing all dissatisfactions
1328
                        // so far. next_sats[j] is either sats[j] + res.nsat (reusing j earlier satisfactions) or sats[j-1] + res.sat
1329
                        // (reusing j-1 earlier satisfactions plus a new one). The very last next_sats[j] is all satisfactions.
1330
84
                        std::vector<InputStack> next_sats;
1331
84
                        next_sats.push_back(sats[0] + res.nsat);
1332
168
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + res.nsat) | (std::move(sats[j - 1]) + res.sat));
1333
84
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
1334
                        // Switch over.
1335
84
                        sats = std::move(next_sats);
1336
84
                    }
1337
                    // At this point, sats[k].sat is the best satisfaction for the overall thresh() node. The best dissatisfaction
1338
                    // is computed by gathering all sats[i].nsat for i != k.
1339
28
                    InputStack nsat = INVALID;
1340
140
                    for (size_t i = 0; i < sats.size(); ++i) {
1341
                        // i==k is the satisfaction; i==0 is the canonical dissatisfaction;
1342
                        // the rest are non-canonical (a no-signature dissatisfaction - the i=0
1343
                        // form - is always available) and malleable (due to overcompleteness).
1344
                        // Marking the solutions malleable here is not strictly necessary, as they
1345
                        // should already never be picked in non-malleable solutions due to the
1346
                        // availability of the i=0 form.
1347
112
                        if (i != 0 && i != node.k) sats[i].SetMalleable().SetNonCanon();
1348
                        // Include all dissatisfactions (even these non-canonical ones) in nsat.
1349
112
                        if (i != node.k) nsat = std::move(nsat) | std::move(sats[i]);
1350
112
                    }
1351
28
                    assert(node.k < sats.size());
1352
28
                    return {std::move(nsat), std::move(sats[node.k])};
1353
28
                }
1354
60
                case Fragment::OLDER: {
1355
60
                    return {INVALID, ctx.CheckOlder(node.k) ? EMPTY : INVALID};
1356
28
                }
1357
428
                case Fragment::AFTER: {
1358
428
                    return {INVALID, ctx.CheckAfter(node.k) ? EMPTY : INVALID};
1359
28
                }
1360
0
                case Fragment::SHA256: {
1361
0
                    std::vector<unsigned char> preimage;
1362
0
                    Availability avail = ctx.SatSHA256(node.data, preimage);
1363
0
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1364
28
                }
1365
0
                case Fragment::RIPEMD160: {
1366
0
                    std::vector<unsigned char> preimage;
1367
0
                    Availability avail = ctx.SatRIPEMD160(node.data, preimage);
1368
0
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1369
28
                }
1370
12
                case Fragment::HASH256: {
1371
12
                    std::vector<unsigned char> preimage;
1372
12
                    Availability avail = ctx.SatHASH256(node.data, preimage);
1373
12
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1374
28
                }
1375
0
                case Fragment::HASH160: {
1376
0
                    std::vector<unsigned char> preimage;
1377
0
                    Availability avail = ctx.SatHASH160(node.data, preimage);
1378
0
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1379
28
                }
1380
552
                case Fragment::AND_V: {
1381
552
                    auto& x = subres[0], &y = subres[1];
1382
                    // As the dissatisfaction here only consist of a single option, it doesn't
1383
                    // actually need to be listed (it's not required for reasoning about malleability of
1384
                    // other options), and is never required (no valid miniscript relies on the ability
1385
                    // to satisfy the type V left subexpression). It's still listed here for
1386
                    // completeness, as a hypothetical (not currently implemented) satisfier that doesn't
1387
                    // care about malleability might in some cases prefer it still.
1388
552
                    return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
1389
28
                }
1390
88
                case Fragment::AND_B: {
1391
88
                    auto& x = subres[0], &y = subres[1];
1392
                    // Note that it is not strictly necessary to mark the 2nd and 3rd dissatisfaction here
1393
                    // as malleable. While they are definitely malleable, they are also non-canonical due
1394
                    // to the guaranteed existence of a no-signature other dissatisfaction (the 1st)
1395
                    // option. Because of that, the 2nd and 3rd option will never be chosen, even if they
1396
                    // weren't marked as malleable.
1397
88
                    return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
1398
28
                }
1399
0
                case Fragment::OR_B: {
1400
0
                    auto& x = subres[0], &z = subres[1];
1401
                    // The (sat(Z) sat(X)) solution is overcomplete (attacker can change either into dsat).
1402
0
                    return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
1403
28
                }
1404
0
                case Fragment::OR_C: {
1405
0
                    auto& x = subres[0], &z = subres[1];
1406
0
                    return {INVALID, std::move(x.sat) | (z.sat + x.nsat)};
1407
28
                }
1408
0
                case Fragment::OR_D: {
1409
0
                    auto& x = subres[0], &z = subres[1];
1410
0
                    return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
1411
28
                }
1412
0
                case Fragment::OR_I: {
1413
0
                    auto& x = subres[0], &z = subres[1];
1414
0
                    return {(x.nsat + ONE) | (z.nsat + ZERO), (x.sat + ONE) | (z.sat + ZERO)};
1415
28
                }
1416
0
                case Fragment::ANDOR: {
1417
0
                    auto& x = subres[0], &y = subres[1], &z = subres[2];
1418
0
                    return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
1419
28
                }
1420
116
                case Fragment::WRAP_A:
1421
144
                case Fragment::WRAP_S:
1422
2.73k
                case Fragment::WRAP_C:
1423
7.25M
                case Fragment::WRAP_N:
1424
7.25M
                    return std::move(subres[0]);
1425
6
                case Fragment::WRAP_D: {
1426
6
                    auto &x = subres[0];
1427
6
                    return {ZERO, x.sat + ONE};
1428
2.73k
                }
1429
0
                case Fragment::WRAP_J: {
1430
0
                    auto &x = subres[0];
1431
                    // If a dissatisfaction with a nonzero top stack element exists, an alternative dissatisfaction exists.
1432
                    // As the dissatisfaction logic currently doesn't keep track of this nonzeroness property, and thus even
1433
                    // if a dissatisfaction with a top zero element is found, we don't know whether another one with a
1434
                    // nonzero top stack element exists. Make the conservative assumption that whenever the subexpression is weakly
1435
                    // dissatisfiable, this alternative dissatisfaction exists and leads to malleability.
1436
0
                    return {InputStack(ZERO).SetMalleable(x.nsat.available != Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
1437
2.73k
                }
1438
558
                case Fragment::WRAP_V: {
1439
558
                    auto &x = subres[0];
1440
558
                    return {INVALID, std::move(x.sat)};
1441
2.73k
                }
1442
0
                case Fragment::JUST_0: return {EMPTY, INVALID};
1443
0
                case Fragment::JUST_1: return {INVALID, EMPTY};
1444
7.25M
            }
1445
7.25M
            assert(false);
1446
0
            return {INVALID, INVALID};
1447
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
1253
3.23k
        auto helper = [&ctx](const Node& node, std::span<InputResult> subres) -> InputResult {
1254
3.23k
            switch (node.fragment) {
1255
474
                case Fragment::PK_K: {
1256
474
                    std::vector<unsigned char> sig;
1257
474
                    Availability avail = ctx.Sign(node.keys[0], sig);
1258
474
                    return {ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
1259
0
                }
1260
61
                case Fragment::PK_H: {
1261
61
                    std::vector<unsigned char> key = ctx.ToPKBytes(node.keys[0]), sig;
1262
61
                    Availability avail = ctx.Sign(node.keys[0], sig);
1263
61
                    return {ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
1264
0
                }
1265
0
                case Fragment::MULTI_A: {
1266
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1267
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1268
0
                    std::vector<InputStack> sats = Vector(EMPTY);
1269
0
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1270
                        // Get the signature for the i'th key in reverse order (the signature for the first key needs to
1271
                        // be at the top of the stack, contrary to CHECKMULTISIG's satisfaction).
1272
0
                        std::vector<unsigned char> sig;
1273
0
                        Availability avail = ctx.Sign(node.keys[node.keys.size() - 1 - i], sig);
1274
                        // Compute signature stack for just this key.
1275
0
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1276
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1277
                        // next_sats[j] are equal to either the existing sats[j] + ZERO, or sats[j-1] plus a signature
1278
                        // for the current (i'th) key. The very last element needs all signatures filled.
1279
0
                        std::vector<InputStack> next_sats;
1280
0
                        next_sats.push_back(sats[0] + ZERO);
1281
0
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + ZERO) | (std::move(sats[j - 1]) + sat));
1282
0
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1283
                        // Switch over.
1284
0
                        sats = std::move(next_sats);
1285
0
                    }
1286
                    // The dissatisfaction consists of as many empty vectors as there are keys, which is the same as
1287
                    // satisfying 0 keys.
1288
0
                    auto& nsat{sats[0]};
1289
0
                    CHECK_NONFATAL(node.k != 0);
1290
0
                    assert(node.k < sats.size());
1291
0
                    return {std::move(nsat), std::move(sats[node.k])};
1292
0
                }
1293
24
                case Fragment::MULTI: {
1294
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1295
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1296
                    // sats[0] starts off being {0}, due to the CHECKMULTISIG bug that pops off one element too many.
1297
24
                    std::vector<InputStack> sats = Vector(ZERO);
1298
72
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1299
48
                        std::vector<unsigned char> sig;
1300
48
                        Availability avail = ctx.Sign(node.keys[i], sig);
1301
                        // Compute signature stack for just the i'th key.
1302
48
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1303
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1304
                        // next_sats[j] are equal to either the existing sats[j], or sats[j-1] plus a signature for the
1305
                        // current (i'th) key. The very last element needs all signatures filled.
1306
48
                        std::vector<InputStack> next_sats;
1307
48
                        next_sats.push_back(sats[0]);
1308
72
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
1309
48
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1310
                        // Switch over.
1311
48
                        sats = std::move(next_sats);
1312
48
                    }
1313
                    // The dissatisfaction consists of k+1 stack elements all equal to 0.
1314
24
                    InputStack nsat = ZERO;
1315
48
                    for (size_t i = 0; i < node.k; ++i) nsat = std::move(nsat) + ZERO;
1316
24
                    assert(node.k < sats.size());
1317
24
                    return {std::move(nsat), std::move(sats[node.k])};
1318
24
                }
1319
105
                case Fragment::THRESH: {
1320
                    // sats[k] represents the best stack that satisfies k out of the *last* i subexpressions.
1321
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1322
                    // sats[0] starts off empty.
1323
105
                    std::vector<InputStack> sats = Vector(EMPTY);
1324
682
                    for (size_t i = 0; i < subres.size(); ++i) {
1325
                        // Introduce an alias for the i'th last satisfaction/dissatisfaction.
1326
577
                        auto& res = subres[subres.size() - i - 1];
1327
                        // Compute the next sats vector: next_sats[0] is sats[0] plus res.nsat (thus containing all dissatisfactions
1328
                        // so far. next_sats[j] is either sats[j] + res.nsat (reusing j earlier satisfactions) or sats[j-1] + res.sat
1329
                        // (reusing j-1 earlier satisfactions plus a new one). The very last next_sats[j] is all satisfactions.
1330
577
                        std::vector<InputStack> next_sats;
1331
577
                        next_sats.push_back(sats[0] + res.nsat);
1332
2.14k
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + res.nsat) | (std::move(sats[j - 1]) + res.sat));
1333
577
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
1334
                        // Switch over.
1335
577
                        sats = std::move(next_sats);
1336
577
                    }
1337
                    // At this point, sats[k].sat is the best satisfaction for the overall thresh() node. The best dissatisfaction
1338
                    // is computed by gathering all sats[i].nsat for i != k.
1339
105
                    InputStack nsat = INVALID;
1340
787
                    for (size_t i = 0; i < sats.size(); ++i) {
1341
                        // i==k is the satisfaction; i==0 is the canonical dissatisfaction;
1342
                        // the rest are non-canonical (a no-signature dissatisfaction - the i=0
1343
                        // form - is always available) and malleable (due to overcompleteness).
1344
                        // Marking the solutions malleable here is not strictly necessary, as they
1345
                        // should already never be picked in non-malleable solutions due to the
1346
                        // availability of the i=0 form.
1347
682
                        if (i != 0 && i != node.k) sats[i].SetMalleable().SetNonCanon();
1348
                        // Include all dissatisfactions (even these non-canonical ones) in nsat.
1349
682
                        if (i != node.k) nsat = std::move(nsat) | std::move(sats[i]);
1350
682
                    }
1351
105
                    assert(node.k < sats.size());
1352
105
                    return {std::move(nsat), std::move(sats[node.k])};
1353
105
                }
1354
87
                case Fragment::OLDER: {
1355
87
                    return {INVALID, ctx.CheckOlder(node.k) ? EMPTY : INVALID};
1356
105
                }
1357
252
                case Fragment::AFTER: {
1358
252
                    return {INVALID, ctx.CheckAfter(node.k) ? EMPTY : INVALID};
1359
105
                }
1360
25
                case Fragment::SHA256: {
1361
25
                    std::vector<unsigned char> preimage;
1362
25
                    Availability avail = ctx.SatSHA256(node.data, preimage);
1363
25
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1364
105
                }
1365
12
                case Fragment::RIPEMD160: {
1366
12
                    std::vector<unsigned char> preimage;
1367
12
                    Availability avail = ctx.SatRIPEMD160(node.data, preimage);
1368
12
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1369
105
                }
1370
12
                case Fragment::HASH256: {
1371
12
                    std::vector<unsigned char> preimage;
1372
12
                    Availability avail = ctx.SatHASH256(node.data, preimage);
1373
12
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1374
105
                }
1375
12
                case Fragment::HASH160: {
1376
12
                    std::vector<unsigned char> preimage;
1377
12
                    Availability avail = ctx.SatHASH160(node.data, preimage);
1378
12
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1379
105
                }
1380
145
                case Fragment::AND_V: {
1381
145
                    auto& x = subres[0], &y = subres[1];
1382
                    // As the dissatisfaction here only consist of a single option, it doesn't
1383
                    // actually need to be listed (it's not required for reasoning about malleability of
1384
                    // other options), and is never required (no valid miniscript relies on the ability
1385
                    // to satisfy the type V left subexpression). It's still listed here for
1386
                    // completeness, as a hypothetical (not currently implemented) satisfier that doesn't
1387
                    // care about malleability might in some cases prefer it still.
1388
145
                    return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
1389
105
                }
1390
8
                case Fragment::AND_B: {
1391
8
                    auto& x = subres[0], &y = subres[1];
1392
                    // Note that it is not strictly necessary to mark the 2nd and 3rd dissatisfaction here
1393
                    // as malleable. While they are definitely malleable, they are also non-canonical due
1394
                    // to the guaranteed existence of a no-signature other dissatisfaction (the 1st)
1395
                    // option. Because of that, the 2nd and 3rd option will never be chosen, even if they
1396
                    // weren't marked as malleable.
1397
8
                    return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
1398
105
                }
1399
0
                case Fragment::OR_B: {
1400
0
                    auto& x = subres[0], &z = subres[1];
1401
                    // The (sat(Z) sat(X)) solution is overcomplete (attacker can change either into dsat).
1402
0
                    return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
1403
105
                }
1404
0
                case Fragment::OR_C: {
1405
0
                    auto& x = subres[0], &z = subres[1];
1406
0
                    return {INVALID, std::move(x.sat) | (z.sat + x.nsat)};
1407
105
                }
1408
4
                case Fragment::OR_D: {
1409
4
                    auto& x = subres[0], &z = subres[1];
1410
4
                    return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
1411
105
                }
1412
223
                case Fragment::OR_I: {
1413
223
                    auto& x = subres[0], &z = subres[1];
1414
223
                    return {(x.nsat + ONE) | (z.nsat + ZERO), (x.sat + ONE) | (z.sat + ZERO)};
1415
105
                }
1416
58
                case Fragment::ANDOR: {
1417
58
                    auto& x = subres[0], &y = subres[1], &z = subres[2];
1418
58
                    return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
1419
105
                }
1420
40
                case Fragment::WRAP_A:
1421
480
                case Fragment::WRAP_S:
1422
1.01k
                case Fragment::WRAP_C:
1423
1.28k
                case Fragment::WRAP_N:
1424
1.28k
                    return std::move(subres[0]);
1425
31
                case Fragment::WRAP_D: {
1426
31
                    auto &x = subres[0];
1427
31
                    return {ZERO, x.sat + ONE};
1428
1.01k
                }
1429
0
                case Fragment::WRAP_J: {
1430
0
                    auto &x = subres[0];
1431
                    // If a dissatisfaction with a nonzero top stack element exists, an alternative dissatisfaction exists.
1432
                    // As the dissatisfaction logic currently doesn't keep track of this nonzeroness property, and thus even
1433
                    // if a dissatisfaction with a top zero element is found, we don't know whether another one with a
1434
                    // nonzero top stack element exists. Make the conservative assumption that whenever the subexpression is weakly
1435
                    // dissatisfiable, this alternative dissatisfaction exists and leads to malleability.
1436
0
                    return {InputStack(ZERO).SetMalleable(x.nsat.available != Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
1437
1.01k
                }
1438
176
                case Fragment::WRAP_V: {
1439
176
                    auto &x = subres[0];
1440
176
                    return {INVALID, std::move(x.sat)};
1441
1.01k
                }
1442
243
                case Fragment::JUST_0: return {EMPTY, INVALID};
1443
0
                case Fragment::JUST_1: return {INVALID, EMPTY};
1444
3.23k
            }
1445
3.23k
            assert(false);
1446
0
            return {INVALID, INVALID};
1447
0
        };
1448
1449
8.87M
        auto tester = [&helper](const Node& node, std::span<InputResult> subres) -> InputResult {
1450
8.87M
            auto ret = helper(node, subres);
1451
1452
            // Do a consistency check between the satisfaction code and the type checker
1453
            // (the actual satisfaction code in ProduceInputHelper does not use GetType)
1454
1455
            // For 'z' nodes, available satisfactions/dissatisfactions must have stack size 0.
1456
8.87M
            if (node.GetType() << "z"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 0);
1457
8.87M
            if (node.GetType() << "z"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 0);
1458
1459
            // For 'o' nodes, available satisfactions/dissatisfactions must have stack size 1.
1460
8.87M
            if (node.GetType() << "o"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 1);
1461
8.87M
            if (node.GetType() << "o"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 1);
1462
1463
            // For 'n' nodes, available satisfactions/dissatisfactions must have stack size 1 or larger. For satisfactions,
1464
            // the top element cannot be 0.
1465
8.87M
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() >= 1);
1466
8.87M
            if (node.GetType() << "n"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() >= 1);
1467
8.87M
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.stack.back().empty());
1468
1469
            // For 'd' nodes, a dissatisfaction must exist, and they must not need a signature. If it is non-malleable,
1470
            // it must be canonical.
1471
8.87M
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1472
8.87M
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(!ret.nsat.has_sig);
1473
8.87M
            if (node.GetType() << "d"_mst && !ret.nsat.malleable) CHECK_NONFATAL(!ret.nsat.non_canon);
1474
1475
            // For 'f'/'s' nodes, dissatisfactions/satisfactions must have a signature.
1476
8.87M
            if (node.GetType() << "f"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.has_sig);
1477
8.87M
            if (node.GetType() << "s"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.has_sig);
1478
1479
            // For non-malleable 'e' nodes, a non-malleable dissatisfaction must exist.
1480
8.87M
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1481
8.87M
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(!ret.nsat.malleable);
1482
1483
            // For 'm' nodes, if a satisfaction exists, it must be non-malleable.
1484
8.87M
            if (node.GetType() << "m"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.malleable);
1485
1486
            // If a non-malleable satisfaction exists, it must be canonical.
1487
8.87M
            if (ret.sat.available != Availability::NO && !ret.sat.malleable) CHECK_NONFATAL(!ret.sat.non_canon);
1488
1489
8.87M
            return ret;
1490
8.87M
        };
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
1449
1.61M
        auto tester = [&helper](const Node& node, std::span<InputResult> subres) -> InputResult {
1450
1.61M
            auto ret = helper(node, subres);
1451
1452
            // Do a consistency check between the satisfaction code and the type checker
1453
            // (the actual satisfaction code in ProduceInputHelper does not use GetType)
1454
1455
            // For 'z' nodes, available satisfactions/dissatisfactions must have stack size 0.
1456
1.61M
            if (node.GetType() << "z"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 0);
1457
1.61M
            if (node.GetType() << "z"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 0);
1458
1459
            // For 'o' nodes, available satisfactions/dissatisfactions must have stack size 1.
1460
1.61M
            if (node.GetType() << "o"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 1);
1461
1.61M
            if (node.GetType() << "o"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 1);
1462
1463
            // For 'n' nodes, available satisfactions/dissatisfactions must have stack size 1 or larger. For satisfactions,
1464
            // the top element cannot be 0.
1465
1.61M
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() >= 1);
1466
1.61M
            if (node.GetType() << "n"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() >= 1);
1467
1.61M
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.stack.back().empty());
1468
1469
            // For 'd' nodes, a dissatisfaction must exist, and they must not need a signature. If it is non-malleable,
1470
            // it must be canonical.
1471
1.61M
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1472
1.61M
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(!ret.nsat.has_sig);
1473
1.61M
            if (node.GetType() << "d"_mst && !ret.nsat.malleable) CHECK_NONFATAL(!ret.nsat.non_canon);
1474
1475
            // For 'f'/'s' nodes, dissatisfactions/satisfactions must have a signature.
1476
1.61M
            if (node.GetType() << "f"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.has_sig);
1477
1.61M
            if (node.GetType() << "s"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.has_sig);
1478
1479
            // For non-malleable 'e' nodes, a non-malleable dissatisfaction must exist.
1480
1.61M
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1481
1.61M
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(!ret.nsat.malleable);
1482
1483
            // For 'm' nodes, if a satisfaction exists, it must be non-malleable.
1484
1.61M
            if (node.GetType() << "m"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.malleable);
1485
1486
            // If a non-malleable satisfaction exists, it must be canonical.
1487
1.61M
            if (ret.sat.available != Availability::NO && !ret.sat.malleable) CHECK_NONFATAL(!ret.sat.non_canon);
1488
1489
1.61M
            return ret;
1490
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
1449
7.25M
        auto tester = [&helper](const Node& node, std::span<InputResult> subres) -> InputResult {
1450
7.25M
            auto ret = helper(node, subres);
1451
1452
            // Do a consistency check between the satisfaction code and the type checker
1453
            // (the actual satisfaction code in ProduceInputHelper does not use GetType)
1454
1455
            // For 'z' nodes, available satisfactions/dissatisfactions must have stack size 0.
1456
7.25M
            if (node.GetType() << "z"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 0);
1457
7.25M
            if (node.GetType() << "z"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 0);
1458
1459
            // For 'o' nodes, available satisfactions/dissatisfactions must have stack size 1.
1460
7.25M
            if (node.GetType() << "o"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 1);
1461
7.25M
            if (node.GetType() << "o"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 1);
1462
1463
            // For 'n' nodes, available satisfactions/dissatisfactions must have stack size 1 or larger. For satisfactions,
1464
            // the top element cannot be 0.
1465
7.25M
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() >= 1);
1466
7.25M
            if (node.GetType() << "n"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() >= 1);
1467
7.25M
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.stack.back().empty());
1468
1469
            // For 'd' nodes, a dissatisfaction must exist, and they must not need a signature. If it is non-malleable,
1470
            // it must be canonical.
1471
7.25M
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1472
7.25M
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(!ret.nsat.has_sig);
1473
7.25M
            if (node.GetType() << "d"_mst && !ret.nsat.malleable) CHECK_NONFATAL(!ret.nsat.non_canon);
1474
1475
            // For 'f'/'s' nodes, dissatisfactions/satisfactions must have a signature.
1476
7.25M
            if (node.GetType() << "f"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.has_sig);
1477
7.25M
            if (node.GetType() << "s"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.has_sig);
1478
1479
            // For non-malleable 'e' nodes, a non-malleable dissatisfaction must exist.
1480
7.25M
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1481
7.25M
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(!ret.nsat.malleable);
1482
1483
            // For 'm' nodes, if a satisfaction exists, it must be non-malleable.
1484
7.25M
            if (node.GetType() << "m"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.malleable);
1485
1486
            // If a non-malleable satisfaction exists, it must be canonical.
1487
7.25M
            if (ret.sat.available != Availability::NO && !ret.sat.malleable) CHECK_NONFATAL(!ret.sat.non_canon);
1488
1489
7.25M
            return ret;
1490
7.25M
        };
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
1449
3.23k
        auto tester = [&helper](const Node& node, std::span<InputResult> subres) -> InputResult {
1450
3.23k
            auto ret = helper(node, subres);
1451
1452
            // Do a consistency check between the satisfaction code and the type checker
1453
            // (the actual satisfaction code in ProduceInputHelper does not use GetType)
1454
1455
            // For 'z' nodes, available satisfactions/dissatisfactions must have stack size 0.
1456
3.23k
            if (node.GetType() << "z"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 0);
1457
3.23k
            if (node.GetType() << "z"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 0);
1458
1459
            // For 'o' nodes, available satisfactions/dissatisfactions must have stack size 1.
1460
3.23k
            if (node.GetType() << "o"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 1);
1461
3.23k
            if (node.GetType() << "o"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 1);
1462
1463
            // For 'n' nodes, available satisfactions/dissatisfactions must have stack size 1 or larger. For satisfactions,
1464
            // the top element cannot be 0.
1465
3.23k
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() >= 1);
1466
3.23k
            if (node.GetType() << "n"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() >= 1);
1467
3.23k
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.stack.back().empty());
1468
1469
            // For 'd' nodes, a dissatisfaction must exist, and they must not need a signature. If it is non-malleable,
1470
            // it must be canonical.
1471
3.23k
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1472
3.23k
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(!ret.nsat.has_sig);
1473
3.23k
            if (node.GetType() << "d"_mst && !ret.nsat.malleable) CHECK_NONFATAL(!ret.nsat.non_canon);
1474
1475
            // For 'f'/'s' nodes, dissatisfactions/satisfactions must have a signature.
1476
3.23k
            if (node.GetType() << "f"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.has_sig);
1477
3.23k
            if (node.GetType() << "s"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.has_sig);
1478
1479
            // For non-malleable 'e' nodes, a non-malleable dissatisfaction must exist.
1480
3.23k
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1481
3.23k
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(!ret.nsat.malleable);
1482
1483
            // For 'm' nodes, if a satisfaction exists, it must be non-malleable.
1484
3.23k
            if (node.GetType() << "m"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.malleable);
1485
1486
            // If a non-malleable satisfaction exists, it must be canonical.
1487
3.23k
            if (ret.sat.available != Availability::NO && !ret.sat.malleable) CHECK_NONFATAL(!ret.sat.non_canon);
1488
1489
3.23k
            return ret;
1490
3.23k
        };
1491
1492
8.22k
        return TreeEval<InputResult>(tester);
1493
8.22k
    }
miniscript_tests.cpp:miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const
Line
Count
Source
1248
4.82k
    internal::InputResult ProduceInput(const Ctx& ctx) const {
1249
4.82k
        using namespace internal;
1250
1251
        // Internal function which is invoked for every tree node, constructing satisfaction/dissatisfactions
1252
        // given those of its subnodes.
1253
4.82k
        auto helper = [&ctx](const Node& node, std::span<InputResult> subres) -> InputResult {
1254
4.82k
            switch (node.fragment) {
1255
4.82k
                case Fragment::PK_K: {
1256
4.82k
                    std::vector<unsigned char> sig;
1257
4.82k
                    Availability avail = ctx.Sign(node.keys[0], sig);
1258
4.82k
                    return {ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
1259
4.82k
                }
1260
4.82k
                case Fragment::PK_H: {
1261
4.82k
                    std::vector<unsigned char> key = ctx.ToPKBytes(node.keys[0]), sig;
1262
4.82k
                    Availability avail = ctx.Sign(node.keys[0], sig);
1263
4.82k
                    return {ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
1264
4.82k
                }
1265
4.82k
                case Fragment::MULTI_A: {
1266
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1267
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1268
4.82k
                    std::vector<InputStack> sats = Vector(EMPTY);
1269
4.82k
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1270
                        // Get the signature for the i'th key in reverse order (the signature for the first key needs to
1271
                        // be at the top of the stack, contrary to CHECKMULTISIG's satisfaction).
1272
4.82k
                        std::vector<unsigned char> sig;
1273
4.82k
                        Availability avail = ctx.Sign(node.keys[node.keys.size() - 1 - i], sig);
1274
                        // Compute signature stack for just this key.
1275
4.82k
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1276
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1277
                        // next_sats[j] are equal to either the existing sats[j] + ZERO, or sats[j-1] plus a signature
1278
                        // for the current (i'th) key. The very last element needs all signatures filled.
1279
4.82k
                        std::vector<InputStack> next_sats;
1280
4.82k
                        next_sats.push_back(sats[0] + ZERO);
1281
4.82k
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + ZERO) | (std::move(sats[j - 1]) + sat));
1282
4.82k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1283
                        // Switch over.
1284
4.82k
                        sats = std::move(next_sats);
1285
4.82k
                    }
1286
                    // The dissatisfaction consists of as many empty vectors as there are keys, which is the same as
1287
                    // satisfying 0 keys.
1288
4.82k
                    auto& nsat{sats[0]};
1289
4.82k
                    CHECK_NONFATAL(node.k != 0);
1290
4.82k
                    assert(node.k < sats.size());
1291
4.82k
                    return {std::move(nsat), std::move(sats[node.k])};
1292
4.82k
                }
1293
4.82k
                case Fragment::MULTI: {
1294
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1295
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1296
                    // sats[0] starts off being {0}, due to the CHECKMULTISIG bug that pops off one element too many.
1297
4.82k
                    std::vector<InputStack> sats = Vector(ZERO);
1298
4.82k
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1299
4.82k
                        std::vector<unsigned char> sig;
1300
4.82k
                        Availability avail = ctx.Sign(node.keys[i], sig);
1301
                        // Compute signature stack for just the i'th key.
1302
4.82k
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1303
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1304
                        // next_sats[j] are equal to either the existing sats[j], or sats[j-1] plus a signature for the
1305
                        // current (i'th) key. The very last element needs all signatures filled.
1306
4.82k
                        std::vector<InputStack> next_sats;
1307
4.82k
                        next_sats.push_back(sats[0]);
1308
4.82k
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
1309
4.82k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1310
                        // Switch over.
1311
4.82k
                        sats = std::move(next_sats);
1312
4.82k
                    }
1313
                    // The dissatisfaction consists of k+1 stack elements all equal to 0.
1314
4.82k
                    InputStack nsat = ZERO;
1315
4.82k
                    for (size_t i = 0; i < node.k; ++i) nsat = std::move(nsat) + ZERO;
1316
4.82k
                    assert(node.k < sats.size());
1317
4.82k
                    return {std::move(nsat), std::move(sats[node.k])};
1318
4.82k
                }
1319
4.82k
                case Fragment::THRESH: {
1320
                    // sats[k] represents the best stack that satisfies k out of the *last* i subexpressions.
1321
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1322
                    // sats[0] starts off empty.
1323
4.82k
                    std::vector<InputStack> sats = Vector(EMPTY);
1324
4.82k
                    for (size_t i = 0; i < subres.size(); ++i) {
1325
                        // Introduce an alias for the i'th last satisfaction/dissatisfaction.
1326
4.82k
                        auto& res = subres[subres.size() - i - 1];
1327
                        // Compute the next sats vector: next_sats[0] is sats[0] plus res.nsat (thus containing all dissatisfactions
1328
                        // so far. next_sats[j] is either sats[j] + res.nsat (reusing j earlier satisfactions) or sats[j-1] + res.sat
1329
                        // (reusing j-1 earlier satisfactions plus a new one). The very last next_sats[j] is all satisfactions.
1330
4.82k
                        std::vector<InputStack> next_sats;
1331
4.82k
                        next_sats.push_back(sats[0] + res.nsat);
1332
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));
1333
4.82k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
1334
                        // Switch over.
1335
4.82k
                        sats = std::move(next_sats);
1336
4.82k
                    }
1337
                    // At this point, sats[k].sat is the best satisfaction for the overall thresh() node. The best dissatisfaction
1338
                    // is computed by gathering all sats[i].nsat for i != k.
1339
4.82k
                    InputStack nsat = INVALID;
1340
4.82k
                    for (size_t i = 0; i < sats.size(); ++i) {
1341
                        // i==k is the satisfaction; i==0 is the canonical dissatisfaction;
1342
                        // the rest are non-canonical (a no-signature dissatisfaction - the i=0
1343
                        // form - is always available) and malleable (due to overcompleteness).
1344
                        // Marking the solutions malleable here is not strictly necessary, as they
1345
                        // should already never be picked in non-malleable solutions due to the
1346
                        // availability of the i=0 form.
1347
4.82k
                        if (i != 0 && i != node.k) sats[i].SetMalleable().SetNonCanon();
1348
                        // Include all dissatisfactions (even these non-canonical ones) in nsat.
1349
4.82k
                        if (i != node.k) nsat = std::move(nsat) | std::move(sats[i]);
1350
4.82k
                    }
1351
4.82k
                    assert(node.k < sats.size());
1352
4.82k
                    return {std::move(nsat), std::move(sats[node.k])};
1353
4.82k
                }
1354
4.82k
                case Fragment::OLDER: {
1355
4.82k
                    return {INVALID, ctx.CheckOlder(node.k) ? EMPTY : INVALID};
1356
4.82k
                }
1357
4.82k
                case Fragment::AFTER: {
1358
4.82k
                    return {INVALID, ctx.CheckAfter(node.k) ? EMPTY : INVALID};
1359
4.82k
                }
1360
4.82k
                case Fragment::SHA256: {
1361
4.82k
                    std::vector<unsigned char> preimage;
1362
4.82k
                    Availability avail = ctx.SatSHA256(node.data, preimage);
1363
4.82k
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1364
4.82k
                }
1365
4.82k
                case Fragment::RIPEMD160: {
1366
4.82k
                    std::vector<unsigned char> preimage;
1367
4.82k
                    Availability avail = ctx.SatRIPEMD160(node.data, preimage);
1368
4.82k
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1369
4.82k
                }
1370
4.82k
                case Fragment::HASH256: {
1371
4.82k
                    std::vector<unsigned char> preimage;
1372
4.82k
                    Availability avail = ctx.SatHASH256(node.data, preimage);
1373
4.82k
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1374
4.82k
                }
1375
4.82k
                case Fragment::HASH160: {
1376
4.82k
                    std::vector<unsigned char> preimage;
1377
4.82k
                    Availability avail = ctx.SatHASH160(node.data, preimage);
1378
4.82k
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1379
4.82k
                }
1380
4.82k
                case Fragment::AND_V: {
1381
4.82k
                    auto& x = subres[0], &y = subres[1];
1382
                    // As the dissatisfaction here only consist of a single option, it doesn't
1383
                    // actually need to be listed (it's not required for reasoning about malleability of
1384
                    // other options), and is never required (no valid miniscript relies on the ability
1385
                    // to satisfy the type V left subexpression). It's still listed here for
1386
                    // completeness, as a hypothetical (not currently implemented) satisfier that doesn't
1387
                    // care about malleability might in some cases prefer it still.
1388
4.82k
                    return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
1389
4.82k
                }
1390
4.82k
                case Fragment::AND_B: {
1391
4.82k
                    auto& x = subres[0], &y = subres[1];
1392
                    // Note that it is not strictly necessary to mark the 2nd and 3rd dissatisfaction here
1393
                    // as malleable. While they are definitely malleable, they are also non-canonical due
1394
                    // to the guaranteed existence of a no-signature other dissatisfaction (the 1st)
1395
                    // option. Because of that, the 2nd and 3rd option will never be chosen, even if they
1396
                    // weren't marked as malleable.
1397
4.82k
                    return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
1398
4.82k
                }
1399
4.82k
                case Fragment::OR_B: {
1400
4.82k
                    auto& x = subres[0], &z = subres[1];
1401
                    // The (sat(Z) sat(X)) solution is overcomplete (attacker can change either into dsat).
1402
4.82k
                    return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
1403
4.82k
                }
1404
4.82k
                case Fragment::OR_C: {
1405
4.82k
                    auto& x = subres[0], &z = subres[1];
1406
4.82k
                    return {INVALID, std::move(x.sat) | (z.sat + x.nsat)};
1407
4.82k
                }
1408
4.82k
                case Fragment::OR_D: {
1409
4.82k
                    auto& x = subres[0], &z = subres[1];
1410
4.82k
                    return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
1411
4.82k
                }
1412
4.82k
                case Fragment::OR_I: {
1413
4.82k
                    auto& x = subres[0], &z = subres[1];
1414
4.82k
                    return {(x.nsat + ONE) | (z.nsat + ZERO), (x.sat + ONE) | (z.sat + ZERO)};
1415
4.82k
                }
1416
4.82k
                case Fragment::ANDOR: {
1417
4.82k
                    auto& x = subres[0], &y = subres[1], &z = subres[2];
1418
4.82k
                    return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
1419
4.82k
                }
1420
4.82k
                case Fragment::WRAP_A:
1421
4.82k
                case Fragment::WRAP_S:
1422
4.82k
                case Fragment::WRAP_C:
1423
4.82k
                case Fragment::WRAP_N:
1424
4.82k
                    return std::move(subres[0]);
1425
4.82k
                case Fragment::WRAP_D: {
1426
4.82k
                    auto &x = subres[0];
1427
4.82k
                    return {ZERO, x.sat + ONE};
1428
4.82k
                }
1429
4.82k
                case Fragment::WRAP_J: {
1430
4.82k
                    auto &x = subres[0];
1431
                    // If a dissatisfaction with a nonzero top stack element exists, an alternative dissatisfaction exists.
1432
                    // As the dissatisfaction logic currently doesn't keep track of this nonzeroness property, and thus even
1433
                    // if a dissatisfaction with a top zero element is found, we don't know whether another one with a
1434
                    // nonzero top stack element exists. Make the conservative assumption that whenever the subexpression is weakly
1435
                    // dissatisfiable, this alternative dissatisfaction exists and leads to malleability.
1436
4.82k
                    return {InputStack(ZERO).SetMalleable(x.nsat.available != Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
1437
4.82k
                }
1438
4.82k
                case Fragment::WRAP_V: {
1439
4.82k
                    auto &x = subres[0];
1440
4.82k
                    return {INVALID, std::move(x.sat)};
1441
4.82k
                }
1442
4.82k
                case Fragment::JUST_0: return {EMPTY, INVALID};
1443
4.82k
                case Fragment::JUST_1: return {INVALID, EMPTY};
1444
4.82k
            }
1445
4.82k
            assert(false);
1446
4.82k
            return {INVALID, INVALID};
1447
4.82k
        };
1448
1449
4.82k
        auto tester = [&helper](const Node& node, std::span<InputResult> subres) -> InputResult {
1450
4.82k
            auto ret = helper(node, subres);
1451
1452
            // Do a consistency check between the satisfaction code and the type checker
1453
            // (the actual satisfaction code in ProduceInputHelper does not use GetType)
1454
1455
            // For 'z' nodes, available satisfactions/dissatisfactions must have stack size 0.
1456
4.82k
            if (node.GetType() << "z"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 0);
1457
4.82k
            if (node.GetType() << "z"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 0);
1458
1459
            // For 'o' nodes, available satisfactions/dissatisfactions must have stack size 1.
1460
4.82k
            if (node.GetType() << "o"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 1);
1461
4.82k
            if (node.GetType() << "o"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 1);
1462
1463
            // For 'n' nodes, available satisfactions/dissatisfactions must have stack size 1 or larger. For satisfactions,
1464
            // the top element cannot be 0.
1465
4.82k
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() >= 1);
1466
4.82k
            if (node.GetType() << "n"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() >= 1);
1467
4.82k
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.stack.back().empty());
1468
1469
            // For 'd' nodes, a dissatisfaction must exist, and they must not need a signature. If it is non-malleable,
1470
            // it must be canonical.
1471
4.82k
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1472
4.82k
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(!ret.nsat.has_sig);
1473
4.82k
            if (node.GetType() << "d"_mst && !ret.nsat.malleable) CHECK_NONFATAL(!ret.nsat.non_canon);
1474
1475
            // For 'f'/'s' nodes, dissatisfactions/satisfactions must have a signature.
1476
4.82k
            if (node.GetType() << "f"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.has_sig);
1477
4.82k
            if (node.GetType() << "s"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.has_sig);
1478
1479
            // For non-malleable 'e' nodes, a non-malleable dissatisfaction must exist.
1480
4.82k
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1481
4.82k
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(!ret.nsat.malleable);
1482
1483
            // For 'm' nodes, if a satisfaction exists, it must be non-malleable.
1484
4.82k
            if (node.GetType() << "m"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.malleable);
1485
1486
            // If a non-malleable satisfaction exists, it must be canonical.
1487
4.82k
            if (ret.sat.available != Availability::NO && !ret.sat.malleable) CHECK_NONFATAL(!ret.sat.non_canon);
1488
1489
4.82k
            return ret;
1490
4.82k
        };
1491
1492
4.82k
        return TreeEval<InputResult>(tester);
1493
4.82k
    }
miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const
Line
Count
Source
1248
3.16k
    internal::InputResult ProduceInput(const Ctx& ctx) const {
1249
3.16k
        using namespace internal;
1250
1251
        // Internal function which is invoked for every tree node, constructing satisfaction/dissatisfactions
1252
        // given those of its subnodes.
1253
3.16k
        auto helper = [&ctx](const Node& node, std::span<InputResult> subres) -> InputResult {
1254
3.16k
            switch (node.fragment) {
1255
3.16k
                case Fragment::PK_K: {
1256
3.16k
                    std::vector<unsigned char> sig;
1257
3.16k
                    Availability avail = ctx.Sign(node.keys[0], sig);
1258
3.16k
                    return {ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
1259
3.16k
                }
1260
3.16k
                case Fragment::PK_H: {
1261
3.16k
                    std::vector<unsigned char> key = ctx.ToPKBytes(node.keys[0]), sig;
1262
3.16k
                    Availability avail = ctx.Sign(node.keys[0], sig);
1263
3.16k
                    return {ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
1264
3.16k
                }
1265
3.16k
                case Fragment::MULTI_A: {
1266
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1267
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1268
3.16k
                    std::vector<InputStack> sats = Vector(EMPTY);
1269
3.16k
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1270
                        // Get the signature for the i'th key in reverse order (the signature for the first key needs to
1271
                        // be at the top of the stack, contrary to CHECKMULTISIG's satisfaction).
1272
3.16k
                        std::vector<unsigned char> sig;
1273
3.16k
                        Availability avail = ctx.Sign(node.keys[node.keys.size() - 1 - i], sig);
1274
                        // Compute signature stack for just this key.
1275
3.16k
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1276
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1277
                        // next_sats[j] are equal to either the existing sats[j] + ZERO, or sats[j-1] plus a signature
1278
                        // for the current (i'th) key. The very last element needs all signatures filled.
1279
3.16k
                        std::vector<InputStack> next_sats;
1280
3.16k
                        next_sats.push_back(sats[0] + ZERO);
1281
3.16k
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + ZERO) | (std::move(sats[j - 1]) + sat));
1282
3.16k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1283
                        // Switch over.
1284
3.16k
                        sats = std::move(next_sats);
1285
3.16k
                    }
1286
                    // The dissatisfaction consists of as many empty vectors as there are keys, which is the same as
1287
                    // satisfying 0 keys.
1288
3.16k
                    auto& nsat{sats[0]};
1289
3.16k
                    CHECK_NONFATAL(node.k != 0);
1290
3.16k
                    assert(node.k < sats.size());
1291
3.16k
                    return {std::move(nsat), std::move(sats[node.k])};
1292
3.16k
                }
1293
3.16k
                case Fragment::MULTI: {
1294
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1295
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1296
                    // sats[0] starts off being {0}, due to the CHECKMULTISIG bug that pops off one element too many.
1297
3.16k
                    std::vector<InputStack> sats = Vector(ZERO);
1298
3.16k
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1299
3.16k
                        std::vector<unsigned char> sig;
1300
3.16k
                        Availability avail = ctx.Sign(node.keys[i], sig);
1301
                        // Compute signature stack for just the i'th key.
1302
3.16k
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1303
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1304
                        // next_sats[j] are equal to either the existing sats[j], or sats[j-1] plus a signature for the
1305
                        // current (i'th) key. The very last element needs all signatures filled.
1306
3.16k
                        std::vector<InputStack> next_sats;
1307
3.16k
                        next_sats.push_back(sats[0]);
1308
3.16k
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
1309
3.16k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1310
                        // Switch over.
1311
3.16k
                        sats = std::move(next_sats);
1312
3.16k
                    }
1313
                    // The dissatisfaction consists of k+1 stack elements all equal to 0.
1314
3.16k
                    InputStack nsat = ZERO;
1315
3.16k
                    for (size_t i = 0; i < node.k; ++i) nsat = std::move(nsat) + ZERO;
1316
3.16k
                    assert(node.k < sats.size());
1317
3.16k
                    return {std::move(nsat), std::move(sats[node.k])};
1318
3.16k
                }
1319
3.16k
                case Fragment::THRESH: {
1320
                    // sats[k] represents the best stack that satisfies k out of the *last* i subexpressions.
1321
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1322
                    // sats[0] starts off empty.
1323
3.16k
                    std::vector<InputStack> sats = Vector(EMPTY);
1324
3.16k
                    for (size_t i = 0; i < subres.size(); ++i) {
1325
                        // Introduce an alias for the i'th last satisfaction/dissatisfaction.
1326
3.16k
                        auto& res = subres[subres.size() - i - 1];
1327
                        // Compute the next sats vector: next_sats[0] is sats[0] plus res.nsat (thus containing all dissatisfactions
1328
                        // so far. next_sats[j] is either sats[j] + res.nsat (reusing j earlier satisfactions) or sats[j-1] + res.sat
1329
                        // (reusing j-1 earlier satisfactions plus a new one). The very last next_sats[j] is all satisfactions.
1330
3.16k
                        std::vector<InputStack> next_sats;
1331
3.16k
                        next_sats.push_back(sats[0] + res.nsat);
1332
3.16k
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + res.nsat) | (std::move(sats[j - 1]) + res.sat));
1333
3.16k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
1334
                        // Switch over.
1335
3.16k
                        sats = std::move(next_sats);
1336
3.16k
                    }
1337
                    // At this point, sats[k].sat is the best satisfaction for the overall thresh() node. The best dissatisfaction
1338
                    // is computed by gathering all sats[i].nsat for i != k.
1339
3.16k
                    InputStack nsat = INVALID;
1340
3.16k
                    for (size_t i = 0; i < sats.size(); ++i) {
1341
                        // i==k is the satisfaction; i==0 is the canonical dissatisfaction;
1342
                        // the rest are non-canonical (a no-signature dissatisfaction - the i=0
1343
                        // form - is always available) and malleable (due to overcompleteness).
1344
                        // Marking the solutions malleable here is not strictly necessary, as they
1345
                        // should already never be picked in non-malleable solutions due to the
1346
                        // availability of the i=0 form.
1347
3.16k
                        if (i != 0 && i != node.k) sats[i].SetMalleable().SetNonCanon();
1348
                        // Include all dissatisfactions (even these non-canonical ones) in nsat.
1349
3.16k
                        if (i != node.k) nsat = std::move(nsat) | std::move(sats[i]);
1350
3.16k
                    }
1351
3.16k
                    assert(node.k < sats.size());
1352
3.16k
                    return {std::move(nsat), std::move(sats[node.k])};
1353
3.16k
                }
1354
3.16k
                case Fragment::OLDER: {
1355
3.16k
                    return {INVALID, ctx.CheckOlder(node.k) ? EMPTY : INVALID};
1356
3.16k
                }
1357
3.16k
                case Fragment::AFTER: {
1358
3.16k
                    return {INVALID, ctx.CheckAfter(node.k) ? EMPTY : INVALID};
1359
3.16k
                }
1360
3.16k
                case Fragment::SHA256: {
1361
3.16k
                    std::vector<unsigned char> preimage;
1362
3.16k
                    Availability avail = ctx.SatSHA256(node.data, preimage);
1363
3.16k
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1364
3.16k
                }
1365
3.16k
                case Fragment::RIPEMD160: {
1366
3.16k
                    std::vector<unsigned char> preimage;
1367
3.16k
                    Availability avail = ctx.SatRIPEMD160(node.data, preimage);
1368
3.16k
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1369
3.16k
                }
1370
3.16k
                case Fragment::HASH256: {
1371
3.16k
                    std::vector<unsigned char> preimage;
1372
3.16k
                    Availability avail = ctx.SatHASH256(node.data, preimage);
1373
3.16k
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1374
3.16k
                }
1375
3.16k
                case Fragment::HASH160: {
1376
3.16k
                    std::vector<unsigned char> preimage;
1377
3.16k
                    Availability avail = ctx.SatHASH160(node.data, preimage);
1378
3.16k
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1379
3.16k
                }
1380
3.16k
                case Fragment::AND_V: {
1381
3.16k
                    auto& x = subres[0], &y = subres[1];
1382
                    // As the dissatisfaction here only consist of a single option, it doesn't
1383
                    // actually need to be listed (it's not required for reasoning about malleability of
1384
                    // other options), and is never required (no valid miniscript relies on the ability
1385
                    // to satisfy the type V left subexpression). It's still listed here for
1386
                    // completeness, as a hypothetical (not currently implemented) satisfier that doesn't
1387
                    // care about malleability might in some cases prefer it still.
1388
3.16k
                    return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
1389
3.16k
                }
1390
3.16k
                case Fragment::AND_B: {
1391
3.16k
                    auto& x = subres[0], &y = subres[1];
1392
                    // Note that it is not strictly necessary to mark the 2nd and 3rd dissatisfaction here
1393
                    // as malleable. While they are definitely malleable, they are also non-canonical due
1394
                    // to the guaranteed existence of a no-signature other dissatisfaction (the 1st)
1395
                    // option. Because of that, the 2nd and 3rd option will never be chosen, even if they
1396
                    // weren't marked as malleable.
1397
3.16k
                    return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
1398
3.16k
                }
1399
3.16k
                case Fragment::OR_B: {
1400
3.16k
                    auto& x = subres[0], &z = subres[1];
1401
                    // The (sat(Z) sat(X)) solution is overcomplete (attacker can change either into dsat).
1402
3.16k
                    return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
1403
3.16k
                }
1404
3.16k
                case Fragment::OR_C: {
1405
3.16k
                    auto& x = subres[0], &z = subres[1];
1406
3.16k
                    return {INVALID, std::move(x.sat) | (z.sat + x.nsat)};
1407
3.16k
                }
1408
3.16k
                case Fragment::OR_D: {
1409
3.16k
                    auto& x = subres[0], &z = subres[1];
1410
3.16k
                    return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
1411
3.16k
                }
1412
3.16k
                case Fragment::OR_I: {
1413
3.16k
                    auto& x = subres[0], &z = subres[1];
1414
3.16k
                    return {(x.nsat + ONE) | (z.nsat + ZERO), (x.sat + ONE) | (z.sat + ZERO)};
1415
3.16k
                }
1416
3.16k
                case Fragment::ANDOR: {
1417
3.16k
                    auto& x = subres[0], &y = subres[1], &z = subres[2];
1418
3.16k
                    return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
1419
3.16k
                }
1420
3.16k
                case Fragment::WRAP_A:
1421
3.16k
                case Fragment::WRAP_S:
1422
3.16k
                case Fragment::WRAP_C:
1423
3.16k
                case Fragment::WRAP_N:
1424
3.16k
                    return std::move(subres[0]);
1425
3.16k
                case Fragment::WRAP_D: {
1426
3.16k
                    auto &x = subres[0];
1427
3.16k
                    return {ZERO, x.sat + ONE};
1428
3.16k
                }
1429
3.16k
                case Fragment::WRAP_J: {
1430
3.16k
                    auto &x = subres[0];
1431
                    // If a dissatisfaction with a nonzero top stack element exists, an alternative dissatisfaction exists.
1432
                    // As the dissatisfaction logic currently doesn't keep track of this nonzeroness property, and thus even
1433
                    // if a dissatisfaction with a top zero element is found, we don't know whether another one with a
1434
                    // nonzero top stack element exists. Make the conservative assumption that whenever the subexpression is weakly
1435
                    // dissatisfiable, this alternative dissatisfaction exists and leads to malleability.
1436
3.16k
                    return {InputStack(ZERO).SetMalleable(x.nsat.available != Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
1437
3.16k
                }
1438
3.16k
                case Fragment::WRAP_V: {
1439
3.16k
                    auto &x = subres[0];
1440
3.16k
                    return {INVALID, std::move(x.sat)};
1441
3.16k
                }
1442
3.16k
                case Fragment::JUST_0: return {EMPTY, INVALID};
1443
3.16k
                case Fragment::JUST_1: return {INVALID, EMPTY};
1444
3.16k
            }
1445
3.16k
            assert(false);
1446
3.16k
            return {INVALID, INVALID};
1447
3.16k
        };
1448
1449
3.16k
        auto tester = [&helper](const Node& node, std::span<InputResult> subres) -> InputResult {
1450
3.16k
            auto ret = helper(node, subres);
1451
1452
            // Do a consistency check between the satisfaction code and the type checker
1453
            // (the actual satisfaction code in ProduceInputHelper does not use GetType)
1454
1455
            // For 'z' nodes, available satisfactions/dissatisfactions must have stack size 0.
1456
3.16k
            if (node.GetType() << "z"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 0);
1457
3.16k
            if (node.GetType() << "z"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 0);
1458
1459
            // For 'o' nodes, available satisfactions/dissatisfactions must have stack size 1.
1460
3.16k
            if (node.GetType() << "o"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 1);
1461
3.16k
            if (node.GetType() << "o"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 1);
1462
1463
            // For 'n' nodes, available satisfactions/dissatisfactions must have stack size 1 or larger. For satisfactions,
1464
            // the top element cannot be 0.
1465
3.16k
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() >= 1);
1466
3.16k
            if (node.GetType() << "n"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() >= 1);
1467
3.16k
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.stack.back().empty());
1468
1469
            // For 'd' nodes, a dissatisfaction must exist, and they must not need a signature. If it is non-malleable,
1470
            // it must be canonical.
1471
3.16k
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1472
3.16k
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(!ret.nsat.has_sig);
1473
3.16k
            if (node.GetType() << "d"_mst && !ret.nsat.malleable) CHECK_NONFATAL(!ret.nsat.non_canon);
1474
1475
            // For 'f'/'s' nodes, dissatisfactions/satisfactions must have a signature.
1476
3.16k
            if (node.GetType() << "f"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.has_sig);
1477
3.16k
            if (node.GetType() << "s"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.has_sig);
1478
1479
            // For non-malleable 'e' nodes, a non-malleable dissatisfaction must exist.
1480
3.16k
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1481
3.16k
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(!ret.nsat.malleable);
1482
1483
            // For 'm' nodes, if a satisfaction exists, it must be non-malleable.
1484
3.16k
            if (node.GetType() << "m"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.malleable);
1485
1486
            // If a non-malleable satisfaction exists, it must be canonical.
1487
3.16k
            if (ret.sat.available != Availability::NO && !ret.sat.malleable) CHECK_NONFATAL(!ret.sat.non_canon);
1488
1489
3.16k
            return ret;
1490
3.16k
        };
1491
1492
3.16k
        return TreeEval<InputResult>(tester);
1493
3.16k
    }
miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const
Line
Count
Source
1248
234
    internal::InputResult ProduceInput(const Ctx& ctx) const {
1249
234
        using namespace internal;
1250
1251
        // Internal function which is invoked for every tree node, constructing satisfaction/dissatisfactions
1252
        // given those of its subnodes.
1253
234
        auto helper = [&ctx](const Node& node, std::span<InputResult> subres) -> InputResult {
1254
234
            switch (node.fragment) {
1255
234
                case Fragment::PK_K: {
1256
234
                    std::vector<unsigned char> sig;
1257
234
                    Availability avail = ctx.Sign(node.keys[0], sig);
1258
234
                    return {ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
1259
234
                }
1260
234
                case Fragment::PK_H: {
1261
234
                    std::vector<unsigned char> key = ctx.ToPKBytes(node.keys[0]), sig;
1262
234
                    Availability avail = ctx.Sign(node.keys[0], sig);
1263
234
                    return {ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
1264
234
                }
1265
234
                case Fragment::MULTI_A: {
1266
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1267
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1268
234
                    std::vector<InputStack> sats = Vector(EMPTY);
1269
234
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1270
                        // Get the signature for the i'th key in reverse order (the signature for the first key needs to
1271
                        // be at the top of the stack, contrary to CHECKMULTISIG's satisfaction).
1272
234
                        std::vector<unsigned char> sig;
1273
234
                        Availability avail = ctx.Sign(node.keys[node.keys.size() - 1 - i], sig);
1274
                        // Compute signature stack for just this key.
1275
234
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1276
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1277
                        // next_sats[j] are equal to either the existing sats[j] + ZERO, or sats[j-1] plus a signature
1278
                        // for the current (i'th) key. The very last element needs all signatures filled.
1279
234
                        std::vector<InputStack> next_sats;
1280
234
                        next_sats.push_back(sats[0] + ZERO);
1281
234
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + ZERO) | (std::move(sats[j - 1]) + sat));
1282
234
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1283
                        // Switch over.
1284
234
                        sats = std::move(next_sats);
1285
234
                    }
1286
                    // The dissatisfaction consists of as many empty vectors as there are keys, which is the same as
1287
                    // satisfying 0 keys.
1288
234
                    auto& nsat{sats[0]};
1289
234
                    CHECK_NONFATAL(node.k != 0);
1290
234
                    assert(node.k < sats.size());
1291
234
                    return {std::move(nsat), std::move(sats[node.k])};
1292
234
                }
1293
234
                case Fragment::MULTI: {
1294
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1295
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1296
                    // sats[0] starts off being {0}, due to the CHECKMULTISIG bug that pops off one element too many.
1297
234
                    std::vector<InputStack> sats = Vector(ZERO);
1298
234
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1299
234
                        std::vector<unsigned char> sig;
1300
234
                        Availability avail = ctx.Sign(node.keys[i], sig);
1301
                        // Compute signature stack for just the i'th key.
1302
234
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1303
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1304
                        // next_sats[j] are equal to either the existing sats[j], or sats[j-1] plus a signature for the
1305
                        // current (i'th) key. The very last element needs all signatures filled.
1306
234
                        std::vector<InputStack> next_sats;
1307
234
                        next_sats.push_back(sats[0]);
1308
234
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
1309
234
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1310
                        // Switch over.
1311
234
                        sats = std::move(next_sats);
1312
234
                    }
1313
                    // The dissatisfaction consists of k+1 stack elements all equal to 0.
1314
234
                    InputStack nsat = ZERO;
1315
234
                    for (size_t i = 0; i < node.k; ++i) nsat = std::move(nsat) + ZERO;
1316
234
                    assert(node.k < sats.size());
1317
234
                    return {std::move(nsat), std::move(sats[node.k])};
1318
234
                }
1319
234
                case Fragment::THRESH: {
1320
                    // sats[k] represents the best stack that satisfies k out of the *last* i subexpressions.
1321
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1322
                    // sats[0] starts off empty.
1323
234
                    std::vector<InputStack> sats = Vector(EMPTY);
1324
234
                    for (size_t i = 0; i < subres.size(); ++i) {
1325
                        // Introduce an alias for the i'th last satisfaction/dissatisfaction.
1326
234
                        auto& res = subres[subres.size() - i - 1];
1327
                        // Compute the next sats vector: next_sats[0] is sats[0] plus res.nsat (thus containing all dissatisfactions
1328
                        // so far. next_sats[j] is either sats[j] + res.nsat (reusing j earlier satisfactions) or sats[j-1] + res.sat
1329
                        // (reusing j-1 earlier satisfactions plus a new one). The very last next_sats[j] is all satisfactions.
1330
234
                        std::vector<InputStack> next_sats;
1331
234
                        next_sats.push_back(sats[0] + res.nsat);
1332
234
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + res.nsat) | (std::move(sats[j - 1]) + res.sat));
1333
234
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
1334
                        // Switch over.
1335
234
                        sats = std::move(next_sats);
1336
234
                    }
1337
                    // At this point, sats[k].sat is the best satisfaction for the overall thresh() node. The best dissatisfaction
1338
                    // is computed by gathering all sats[i].nsat for i != k.
1339
234
                    InputStack nsat = INVALID;
1340
234
                    for (size_t i = 0; i < sats.size(); ++i) {
1341
                        // i==k is the satisfaction; i==0 is the canonical dissatisfaction;
1342
                        // the rest are non-canonical (a no-signature dissatisfaction - the i=0
1343
                        // form - is always available) and malleable (due to overcompleteness).
1344
                        // Marking the solutions malleable here is not strictly necessary, as they
1345
                        // should already never be picked in non-malleable solutions due to the
1346
                        // availability of the i=0 form.
1347
234
                        if (i != 0 && i != node.k) sats[i].SetMalleable().SetNonCanon();
1348
                        // Include all dissatisfactions (even these non-canonical ones) in nsat.
1349
234
                        if (i != node.k) nsat = std::move(nsat) | std::move(sats[i]);
1350
234
                    }
1351
234
                    assert(node.k < sats.size());
1352
234
                    return {std::move(nsat), std::move(sats[node.k])};
1353
234
                }
1354
234
                case Fragment::OLDER: {
1355
234
                    return {INVALID, ctx.CheckOlder(node.k) ? EMPTY : INVALID};
1356
234
                }
1357
234
                case Fragment::AFTER: {
1358
234
                    return {INVALID, ctx.CheckAfter(node.k) ? EMPTY : INVALID};
1359
234
                }
1360
234
                case Fragment::SHA256: {
1361
234
                    std::vector<unsigned char> preimage;
1362
234
                    Availability avail = ctx.SatSHA256(node.data, preimage);
1363
234
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1364
234
                }
1365
234
                case Fragment::RIPEMD160: {
1366
234
                    std::vector<unsigned char> preimage;
1367
234
                    Availability avail = ctx.SatRIPEMD160(node.data, preimage);
1368
234
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1369
234
                }
1370
234
                case Fragment::HASH256: {
1371
234
                    std::vector<unsigned char> preimage;
1372
234
                    Availability avail = ctx.SatHASH256(node.data, preimage);
1373
234
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1374
234
                }
1375
234
                case Fragment::HASH160: {
1376
234
                    std::vector<unsigned char> preimage;
1377
234
                    Availability avail = ctx.SatHASH160(node.data, preimage);
1378
234
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1379
234
                }
1380
234
                case Fragment::AND_V: {
1381
234
                    auto& x = subres[0], &y = subres[1];
1382
                    // As the dissatisfaction here only consist of a single option, it doesn't
1383
                    // actually need to be listed (it's not required for reasoning about malleability of
1384
                    // other options), and is never required (no valid miniscript relies on the ability
1385
                    // to satisfy the type V left subexpression). It's still listed here for
1386
                    // completeness, as a hypothetical (not currently implemented) satisfier that doesn't
1387
                    // care about malleability might in some cases prefer it still.
1388
234
                    return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
1389
234
                }
1390
234
                case Fragment::AND_B: {
1391
234
                    auto& x = subres[0], &y = subres[1];
1392
                    // Note that it is not strictly necessary to mark the 2nd and 3rd dissatisfaction here
1393
                    // as malleable. While they are definitely malleable, they are also non-canonical due
1394
                    // to the guaranteed existence of a no-signature other dissatisfaction (the 1st)
1395
                    // option. Because of that, the 2nd and 3rd option will never be chosen, even if they
1396
                    // weren't marked as malleable.
1397
234
                    return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
1398
234
                }
1399
234
                case Fragment::OR_B: {
1400
234
                    auto& x = subres[0], &z = subres[1];
1401
                    // The (sat(Z) sat(X)) solution is overcomplete (attacker can change either into dsat).
1402
234
                    return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
1403
234
                }
1404
234
                case Fragment::OR_C: {
1405
234
                    auto& x = subres[0], &z = subres[1];
1406
234
                    return {INVALID, std::move(x.sat) | (z.sat + x.nsat)};
1407
234
                }
1408
234
                case Fragment::OR_D: {
1409
234
                    auto& x = subres[0], &z = subres[1];
1410
234
                    return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
1411
234
                }
1412
234
                case Fragment::OR_I: {
1413
234
                    auto& x = subres[0], &z = subres[1];
1414
234
                    return {(x.nsat + ONE) | (z.nsat + ZERO), (x.sat + ONE) | (z.sat + ZERO)};
1415
234
                }
1416
234
                case Fragment::ANDOR: {
1417
234
                    auto& x = subres[0], &y = subres[1], &z = subres[2];
1418
234
                    return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
1419
234
                }
1420
234
                case Fragment::WRAP_A:
1421
234
                case Fragment::WRAP_S:
1422
234
                case Fragment::WRAP_C:
1423
234
                case Fragment::WRAP_N:
1424
234
                    return std::move(subres[0]);
1425
234
                case Fragment::WRAP_D: {
1426
234
                    auto &x = subres[0];
1427
234
                    return {ZERO, x.sat + ONE};
1428
234
                }
1429
234
                case Fragment::WRAP_J: {
1430
234
                    auto &x = subres[0];
1431
                    // If a dissatisfaction with a nonzero top stack element exists, an alternative dissatisfaction exists.
1432
                    // As the dissatisfaction logic currently doesn't keep track of this nonzeroness property, and thus even
1433
                    // if a dissatisfaction with a top zero element is found, we don't know whether another one with a
1434
                    // nonzero top stack element exists. Make the conservative assumption that whenever the subexpression is weakly
1435
                    // dissatisfiable, this alternative dissatisfaction exists and leads to malleability.
1436
234
                    return {InputStack(ZERO).SetMalleable(x.nsat.available != Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
1437
234
                }
1438
234
                case Fragment::WRAP_V: {
1439
234
                    auto &x = subres[0];
1440
234
                    return {INVALID, std::move(x.sat)};
1441
234
                }
1442
234
                case Fragment::JUST_0: return {EMPTY, INVALID};
1443
234
                case Fragment::JUST_1: return {INVALID, EMPTY};
1444
234
            }
1445
234
            assert(false);
1446
234
            return {INVALID, INVALID};
1447
234
        };
1448
1449
234
        auto tester = [&helper](const Node& node, std::span<InputResult> subres) -> InputResult {
1450
234
            auto ret = helper(node, subres);
1451
1452
            // Do a consistency check between the satisfaction code and the type checker
1453
            // (the actual satisfaction code in ProduceInputHelper does not use GetType)
1454
1455
            // For 'z' nodes, available satisfactions/dissatisfactions must have stack size 0.
1456
234
            if (node.GetType() << "z"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 0);
1457
234
            if (node.GetType() << "z"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 0);
1458
1459
            // For 'o' nodes, available satisfactions/dissatisfactions must have stack size 1.
1460
234
            if (node.GetType() << "o"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 1);
1461
234
            if (node.GetType() << "o"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 1);
1462
1463
            // For 'n' nodes, available satisfactions/dissatisfactions must have stack size 1 or larger. For satisfactions,
1464
            // the top element cannot be 0.
1465
234
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() >= 1);
1466
234
            if (node.GetType() << "n"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() >= 1);
1467
234
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.stack.back().empty());
1468
1469
            // For 'd' nodes, a dissatisfaction must exist, and they must not need a signature. If it is non-malleable,
1470
            // it must be canonical.
1471
234
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1472
234
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(!ret.nsat.has_sig);
1473
234
            if (node.GetType() << "d"_mst && !ret.nsat.malleable) CHECK_NONFATAL(!ret.nsat.non_canon);
1474
1475
            // For 'f'/'s' nodes, dissatisfactions/satisfactions must have a signature.
1476
234
            if (node.GetType() << "f"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.has_sig);
1477
234
            if (node.GetType() << "s"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.has_sig);
1478
1479
            // For non-malleable 'e' nodes, a non-malleable dissatisfaction must exist.
1480
234
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1481
234
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(!ret.nsat.malleable);
1482
1483
            // For 'm' nodes, if a satisfaction exists, it must be non-malleable.
1484
234
            if (node.GetType() << "m"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.malleable);
1485
1486
            // If a non-malleable satisfaction exists, it must be canonical.
1487
234
            if (ret.sat.available != Availability::NO && !ret.sat.malleable) CHECK_NONFATAL(!ret.sat.non_canon);
1488
1489
234
            return ret;
1490
234
        };
1491
1492
234
        return TreeEval<InputResult>(tester);
1493
234
    }
1494
1495
public:
1496
    /** Update duplicate key information in this Node.
1497
     *
1498
     * This uses a custom key comparator provided by the context in order to still detect duplicates
1499
     * for more complicated types.
1500
     */
1501
    template<typename Ctx> void DuplicateKeyCheck(const Ctx& ctx) const
1502
4.49k
    {
1503
        // We cannot use a lambda here, as lambdas are non assignable, and the set operations
1504
        // below require moving the comparators around.
1505
4.49k
        struct Comp {
1506
4.49k
            const Ctx* ctx_ptr;
1507
8.27M
            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
1507
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
1507
995k
            Comp(const Ctx& ctx) : ctx_ptr(&ctx) {}
void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp::Comp(TapSatisfier const&)
Line
Count
Source
1507
7.25M
            Comp(const Ctx& ctx) : ctx_ptr(&ctx) {}
void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp::Comp(WshSatisfier const&)
Line
Count
Source
1507
3.23k
            Comp(const Ctx& ctx) : ctx_ptr(&ctx) {}
1508
285k
            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
1508
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
1508
4.20k
            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
1508
272k
            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
1508
1.12k
            bool operator()(const Key& a, const Key& b) const { return ctx_ptr->KeyCompare(a, b); }
1509
4.49k
        };
1510
1511
        // state in the recursive computation:
1512
        // - std::nullopt means "this node has duplicates"
1513
        // - an std::set means "this node has no duplicate keys, and they are: ...".
1514
4.49k
        using keyset = std::set<Key, Comp>;
1515
4.49k
        using state = std::optional<keyset>;
1516
1517
8.27M
        auto upfn = [&ctx](const Node& node, std::span<state> subs) -> state {
1518
            // If this node is already known to have duplicates, nothing left to do.
1519
8.27M
            if (node.has_duplicate_keys.has_value() && *node.has_duplicate_keys) return {};
1520
1521
            // Check if one of the children is already known to have duplicates.
1522
8.27M
            for (auto& sub : subs) {
1523
8.27M
                if (!sub.has_value()) {
1524
0
                    node.has_duplicate_keys = true;
1525
0
                    return {};
1526
0
                }
1527
8.27M
            }
1528
1529
            // Start building the set of keys involved in this node and children.
1530
            // Start by keys in this node directly.
1531
8.27M
            size_t keys_count = node.keys.size();
1532
8.27M
            keyset key_set{node.keys.begin(), node.keys.end(), Comp(ctx)};
1533
8.27M
            if (key_set.size() != keys_count) {
1534
                // It already has duplicates; bail out.
1535
89
                node.has_duplicate_keys = true;
1536
89
                return {};
1537
89
            }
1538
1539
            // Merge the keys from the children into this set.
1540
8.27M
            for (auto& sub : subs) {
1541
8.27M
                keys_count += sub->size();
1542
                // Small optimization: std::set::merge is linear in the size of the second arg but
1543
                // logarithmic in the size of the first.
1544
8.27M
                if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1545
8.27M
                key_set.merge(*sub);
1546
8.27M
                if (key_set.size() != keys_count) {
1547
8
                    node.has_duplicate_keys = true;
1548
8
                    return {};
1549
8
                }
1550
8.27M
            }
1551
1552
8.27M
            node.has_duplicate_keys = false;
1553
8.27M
            return key_set;
1554
8.27M
        };
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
1517
23.2k
        auto upfn = [&ctx](const Node& node, std::span<state> subs) -> state {
1518
            // If this node is already known to have duplicates, nothing left to do.
1519
23.2k
            if (node.has_duplicate_keys.has_value() && *node.has_duplicate_keys) return {};
1520
1521
            // Check if one of the children is already known to have duplicates.
1522
23.2k
            for (auto& sub : subs) {
1523
22.9k
                if (!sub.has_value()) {
1524
0
                    node.has_duplicate_keys = true;
1525
0
                    return {};
1526
0
                }
1527
22.9k
            }
1528
1529
            // Start building the set of keys involved in this node and children.
1530
            // Start by keys in this node directly.
1531
23.2k
            size_t keys_count = node.keys.size();
1532
23.2k
            keyset key_set{node.keys.begin(), node.keys.end(), Comp(ctx)};
1533
23.2k
            if (key_set.size() != keys_count) {
1534
                // It already has duplicates; bail out.
1535
0
                node.has_duplicate_keys = true;
1536
0
                return {};
1537
0
            }
1538
1539
            // Merge the keys from the children into this set.
1540
23.2k
            for (auto& sub : subs) {
1541
22.9k
                keys_count += sub->size();
1542
                // Small optimization: std::set::merge is linear in the size of the second arg but
1543
                // logarithmic in the size of the first.
1544
22.9k
                if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1545
22.9k
                key_set.merge(*sub);
1546
22.9k
                if (key_set.size() != keys_count) {
1547
6
                    node.has_duplicate_keys = true;
1548
6
                    return {};
1549
6
                }
1550
22.9k
            }
1551
1552
23.2k
            node.has_duplicate_keys = false;
1553
23.2k
            return key_set;
1554
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
1517
995k
        auto upfn = [&ctx](const Node& node, std::span<state> subs) -> state {
1518
            // If this node is already known to have duplicates, nothing left to do.
1519
995k
            if (node.has_duplicate_keys.has_value() && *node.has_duplicate_keys) return {};
1520
1521
            // Check if one of the children is already known to have duplicates.
1522
995k
            for (auto& sub : subs) {
1523
994k
                if (!sub.has_value()) {
1524
0
                    node.has_duplicate_keys = true;
1525
0
                    return {};
1526
0
                }
1527
994k
            }
1528
1529
            // Start building the set of keys involved in this node and children.
1530
            // Start by keys in this node directly.
1531
995k
            size_t keys_count = node.keys.size();
1532
995k
            keyset key_set{node.keys.begin(), node.keys.end(), Comp(ctx)};
1533
995k
            if (key_set.size() != keys_count) {
1534
                // It already has duplicates; bail out.
1535
0
                node.has_duplicate_keys = true;
1536
0
                return {};
1537
0
            }
1538
1539
            // Merge the keys from the children into this set.
1540
995k
            for (auto& sub : subs) {
1541
994k
                keys_count += sub->size();
1542
                // Small optimization: std::set::merge is linear in the size of the second arg but
1543
                // logarithmic in the size of the first.
1544
994k
                if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1545
994k
                key_set.merge(*sub);
1546
994k
                if (key_set.size() != keys_count) {
1547
2
                    node.has_duplicate_keys = true;
1548
2
                    return {};
1549
2
                }
1550
994k
            }
1551
1552
995k
            node.has_duplicate_keys = false;
1553
995k
            return key_set;
1554
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
1517
7.25M
        auto upfn = [&ctx](const Node& node, std::span<state> subs) -> state {
1518
            // If this node is already known to have duplicates, nothing left to do.
1519
7.25M
            if (node.has_duplicate_keys.has_value() && *node.has_duplicate_keys) return {};
1520
1521
            // Check if one of the children is already known to have duplicates.
1522
7.25M
            for (auto& sub : subs) {
1523
7.25M
                if (!sub.has_value()) {
1524
0
                    node.has_duplicate_keys = true;
1525
0
                    return {};
1526
0
                }
1527
7.25M
            }
1528
1529
            // Start building the set of keys involved in this node and children.
1530
            // Start by keys in this node directly.
1531
7.25M
            size_t keys_count = node.keys.size();
1532
7.25M
            keyset key_set{node.keys.begin(), node.keys.end(), Comp(ctx)};
1533
7.25M
            if (key_set.size() != keys_count) {
1534
                // It already has duplicates; bail out.
1535
89
                node.has_duplicate_keys = true;
1536
89
                return {};
1537
89
            }
1538
1539
            // Merge the keys from the children into this set.
1540
7.25M
            for (auto& sub : subs) {
1541
7.25M
                keys_count += sub->size();
1542
                // Small optimization: std::set::merge is linear in the size of the second arg but
1543
                // logarithmic in the size of the first.
1544
7.25M
                if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1545
7.25M
                key_set.merge(*sub);
1546
7.25M
                if (key_set.size() != keys_count) {
1547
0
                    node.has_duplicate_keys = true;
1548
0
                    return {};
1549
0
                }
1550
7.25M
            }
1551
1552
7.25M
            node.has_duplicate_keys = false;
1553
7.25M
            return key_set;
1554
7.25M
        };
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
1517
3.23k
        auto upfn = [&ctx](const Node& node, std::span<state> subs) -> state {
1518
            // If this node is already known to have duplicates, nothing left to do.
1519
3.23k
            if (node.has_duplicate_keys.has_value() && *node.has_duplicate_keys) return {};
1520
1521
            // Check if one of the children is already known to have duplicates.
1522
3.23k
            for (auto& sub : subs) {
1523
3.00k
                if (!sub.has_value()) {
1524
0
                    node.has_duplicate_keys = true;
1525
0
                    return {};
1526
0
                }
1527
3.00k
            }
1528
1529
            // Start building the set of keys involved in this node and children.
1530
            // Start by keys in this node directly.
1531
3.23k
            size_t keys_count = node.keys.size();
1532
3.23k
            keyset key_set{node.keys.begin(), node.keys.end(), Comp(ctx)};
1533
3.23k
            if (key_set.size() != keys_count) {
1534
                // It already has duplicates; bail out.
1535
0
                node.has_duplicate_keys = true;
1536
0
                return {};
1537
0
            }
1538
1539
            // Merge the keys from the children into this set.
1540
3.23k
            for (auto& sub : subs) {
1541
3.00k
                keys_count += sub->size();
1542
                // Small optimization: std::set::merge is linear in the size of the second arg but
1543
                // logarithmic in the size of the first.
1544
3.00k
                if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1545
3.00k
                key_set.merge(*sub);
1546
3.00k
                if (key_set.size() != keys_count) {
1547
0
                    node.has_duplicate_keys = true;
1548
0
                    return {};
1549
0
                }
1550
3.00k
            }
1551
1552
3.23k
            node.has_duplicate_keys = false;
1553
3.23k
            return key_set;
1554
3.23k
        };
1555
1556
4.49k
        TreeEval<state>(upfn);
1557
4.49k
    }
miniscript_tests.cpp:void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const
Line
Count
Source
1502
313
    {
1503
        // We cannot use a lambda here, as lambdas are non assignable, and the set operations
1504
        // below require moving the comparators around.
1505
313
        struct Comp {
1506
313
            const Ctx* ctx_ptr;
1507
313
            Comp(const Ctx& ctx) : ctx_ptr(&ctx) {}
1508
313
            bool operator()(const Key& a, const Key& b) const { return ctx_ptr->KeyCompare(a, b); }
1509
313
        };
1510
1511
        // state in the recursive computation:
1512
        // - std::nullopt means "this node has duplicates"
1513
        // - an std::set means "this node has no duplicate keys, and they are: ...".
1514
313
        using keyset = std::set<Key, Comp>;
1515
313
        using state = std::optional<keyset>;
1516
1517
313
        auto upfn = [&ctx](const Node& node, std::span<state> subs) -> state {
1518
            // If this node is already known to have duplicates, nothing left to do.
1519
313
            if (node.has_duplicate_keys.has_value() && *node.has_duplicate_keys) return {};
1520
1521
            // Check if one of the children is already known to have duplicates.
1522
313
            for (auto& sub : subs) {
1523
313
                if (!sub.has_value()) {
1524
313
                    node.has_duplicate_keys = true;
1525
313
                    return {};
1526
313
                }
1527
313
            }
1528
1529
            // Start building the set of keys involved in this node and children.
1530
            // Start by keys in this node directly.
1531
313
            size_t keys_count = node.keys.size();
1532
313
            keyset key_set{node.keys.begin(), node.keys.end(), Comp(ctx)};
1533
313
            if (key_set.size() != keys_count) {
1534
                // It already has duplicates; bail out.
1535
313
                node.has_duplicate_keys = true;
1536
313
                return {};
1537
313
            }
1538
1539
            // Merge the keys from the children into this set.
1540
313
            for (auto& sub : subs) {
1541
313
                keys_count += sub->size();
1542
                // Small optimization: std::set::merge is linear in the size of the second arg but
1543
                // logarithmic in the size of the first.
1544
313
                if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1545
313
                key_set.merge(*sub);
1546
313
                if (key_set.size() != keys_count) {
1547
313
                    node.has_duplicate_keys = true;
1548
313
                    return {};
1549
313
                }
1550
313
            }
1551
1552
313
            node.has_duplicate_keys = false;
1553
313
            return key_set;
1554
313
        };
1555
1556
313
        TreeEval<state>(upfn);
1557
313
    }
descriptor.cpp:void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const
Line
Count
Source
1502
783
    {
1503
        // We cannot use a lambda here, as lambdas are non assignable, and the set operations
1504
        // below require moving the comparators around.
1505
783
        struct Comp {
1506
783
            const Ctx* ctx_ptr;
1507
783
            Comp(const Ctx& ctx) : ctx_ptr(&ctx) {}
1508
783
            bool operator()(const Key& a, const Key& b) const { return ctx_ptr->KeyCompare(a, b); }
1509
783
        };
1510
1511
        // state in the recursive computation:
1512
        // - std::nullopt means "this node has duplicates"
1513
        // - an std::set means "this node has no duplicate keys, and they are: ...".
1514
783
        using keyset = std::set<Key, Comp>;
1515
783
        using state = std::optional<keyset>;
1516
1517
783
        auto upfn = [&ctx](const Node& node, std::span<state> subs) -> state {
1518
            // If this node is already known to have duplicates, nothing left to do.
1519
783
            if (node.has_duplicate_keys.has_value() && *node.has_duplicate_keys) return {};
1520
1521
            // Check if one of the children is already known to have duplicates.
1522
783
            for (auto& sub : subs) {
1523
783
                if (!sub.has_value()) {
1524
783
                    node.has_duplicate_keys = true;
1525
783
                    return {};
1526
783
                }
1527
783
            }
1528
1529
            // Start building the set of keys involved in this node and children.
1530
            // Start by keys in this node directly.
1531
783
            size_t keys_count = node.keys.size();
1532
783
            keyset key_set{node.keys.begin(), node.keys.end(), Comp(ctx)};
1533
783
            if (key_set.size() != keys_count) {
1534
                // It already has duplicates; bail out.
1535
783
                node.has_duplicate_keys = true;
1536
783
                return {};
1537
783
            }
1538
1539
            // Merge the keys from the children into this set.
1540
783
            for (auto& sub : subs) {
1541
783
                keys_count += sub->size();
1542
                // Small optimization: std::set::merge is linear in the size of the second arg but
1543
                // logarithmic in the size of the first.
1544
783
                if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1545
783
                key_set.merge(*sub);
1546
783
                if (key_set.size() != keys_count) {
1547
783
                    node.has_duplicate_keys = true;
1548
783
                    return {};
1549
783
                }
1550
783
            }
1551
1552
783
            node.has_duplicate_keys = false;
1553
783
            return key_set;
1554
783
        };
1555
1556
783
        TreeEval<state>(upfn);
1557
783
    }
void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const
Line
Count
Source
1502
3.16k
    {
1503
        // We cannot use a lambda here, as lambdas are non assignable, and the set operations
1504
        // below require moving the comparators around.
1505
3.16k
        struct Comp {
1506
3.16k
            const Ctx* ctx_ptr;
1507
3.16k
            Comp(const Ctx& ctx) : ctx_ptr(&ctx) {}
1508
3.16k
            bool operator()(const Key& a, const Key& b) const { return ctx_ptr->KeyCompare(a, b); }
1509
3.16k
        };
1510
1511
        // state in the recursive computation:
1512
        // - std::nullopt means "this node has duplicates"
1513
        // - an std::set means "this node has no duplicate keys, and they are: ...".
1514
3.16k
        using keyset = std::set<Key, Comp>;
1515
3.16k
        using state = std::optional<keyset>;
1516
1517
3.16k
        auto upfn = [&ctx](const Node& node, std::span<state> subs) -> state {
1518
            // If this node is already known to have duplicates, nothing left to do.
1519
3.16k
            if (node.has_duplicate_keys.has_value() && *node.has_duplicate_keys) return {};
1520
1521
            // Check if one of the children is already known to have duplicates.
1522
3.16k
            for (auto& sub : subs) {
1523
3.16k
                if (!sub.has_value()) {
1524
3.16k
                    node.has_duplicate_keys = true;
1525
3.16k
                    return {};
1526
3.16k
                }
1527
3.16k
            }
1528
1529
            // Start building the set of keys involved in this node and children.
1530
            // Start by keys in this node directly.
1531
3.16k
            size_t keys_count = node.keys.size();
1532
3.16k
            keyset key_set{node.keys.begin(), node.keys.end(), Comp(ctx)};
1533
3.16k
            if (key_set.size() != keys_count) {
1534
                // It already has duplicates; bail out.
1535
3.16k
                node.has_duplicate_keys = true;
1536
3.16k
                return {};
1537
3.16k
            }
1538
1539
            // Merge the keys from the children into this set.
1540
3.16k
            for (auto& sub : subs) {
1541
3.16k
                keys_count += sub->size();
1542
                // Small optimization: std::set::merge is linear in the size of the second arg but
1543
                // logarithmic in the size of the first.
1544
3.16k
                if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1545
3.16k
                key_set.merge(*sub);
1546
3.16k
                if (key_set.size() != keys_count) {
1547
3.16k
                    node.has_duplicate_keys = true;
1548
3.16k
                    return {};
1549
3.16k
                }
1550
3.16k
            }
1551
1552
3.16k
            node.has_duplicate_keys = false;
1553
3.16k
            return key_set;
1554
3.16k
        };
1555
1556
3.16k
        TreeEval<state>(upfn);
1557
3.16k
    }
void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const
Line
Count
Source
1502
234
    {
1503
        // We cannot use a lambda here, as lambdas are non assignable, and the set operations
1504
        // below require moving the comparators around.
1505
234
        struct Comp {
1506
234
            const Ctx* ctx_ptr;
1507
234
            Comp(const Ctx& ctx) : ctx_ptr(&ctx) {}
1508
234
            bool operator()(const Key& a, const Key& b) const { return ctx_ptr->KeyCompare(a, b); }
1509
234
        };
1510
1511
        // state in the recursive computation:
1512
        // - std::nullopt means "this node has duplicates"
1513
        // - an std::set means "this node has no duplicate keys, and they are: ...".
1514
234
        using keyset = std::set<Key, Comp>;
1515
234
        using state = std::optional<keyset>;
1516
1517
234
        auto upfn = [&ctx](const Node& node, std::span<state> subs) -> state {
1518
            // If this node is already known to have duplicates, nothing left to do.
1519
234
            if (node.has_duplicate_keys.has_value() && *node.has_duplicate_keys) return {};
1520
1521
            // Check if one of the children is already known to have duplicates.
1522
234
            for (auto& sub : subs) {
1523
234
                if (!sub.has_value()) {
1524
234
                    node.has_duplicate_keys = true;
1525
234
                    return {};
1526
234
                }
1527
234
            }
1528
1529
            // Start building the set of keys involved in this node and children.
1530
            // Start by keys in this node directly.
1531
234
            size_t keys_count = node.keys.size();
1532
234
            keyset key_set{node.keys.begin(), node.keys.end(), Comp(ctx)};
1533
234
            if (key_set.size() != keys_count) {
1534
                // It already has duplicates; bail out.
1535
234
                node.has_duplicate_keys = true;
1536
234
                return {};
1537
234
            }
1538
1539
            // Merge the keys from the children into this set.
1540
234
            for (auto& sub : subs) {
1541
234
                keys_count += sub->size();
1542
                // Small optimization: std::set::merge is linear in the size of the second arg but
1543
                // logarithmic in the size of the first.
1544
234
                if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1545
234
                key_set.merge(*sub);
1546
234
                if (key_set.size() != keys_count) {
1547
234
                    node.has_duplicate_keys = true;
1548
234
                    return {};
1549
234
                }
1550
234
            }
1551
1552
234
            node.has_duplicate_keys = false;
1553
234
            return key_set;
1554
234
        };
1555
1556
234
        TreeEval<state>(upfn);
1557
234
    }
1558
1559
    //! Return the size of the script for this expression (faster than ToScript().size()).
1560
16.9M
    size_t ScriptSize() const { return scriptlen; }
miniscript::Node<CPubKey>::ScriptSize() const
Line
Count
Source
1560
57.7k
    size_t ScriptSize() const { return scriptlen; }
miniscript::Node<unsigned int>::ScriptSize() const
Line
Count
Source
1560
2.39M
    size_t ScriptSize() const { return scriptlen; }
miniscript::Node<XOnlyPubKey>::ScriptSize() const
Line
Count
Source
1560
14.5M
    size_t ScriptSize() const { return scriptlen; }
1561
1562
    //! Return the maximum number of ops needed to satisfy this script non-malleably.
1563
2.16k
    std::optional<uint32_t> GetOps() const {
1564
2.16k
        if (!ops.sat.Valid()) return {};
1565
2.15k
        return ops.count + ops.sat.Value();
1566
2.16k
    }
miniscript::Node<CPubKey>::GetOps() const
Line
Count
Source
1563
1.62k
    std::optional<uint32_t> GetOps() const {
1564
1.62k
        if (!ops.sat.Valid()) return {};
1565
1.61k
        return ops.count + ops.sat.Value();
1566
1.62k
    }
miniscript::Node<unsigned int>::GetOps() const
Line
Count
Source
1563
540
    std::optional<uint32_t> GetOps() const {
1564
540
        if (!ops.sat.Valid()) return {};
1565
537
        return ops.count + ops.sat.Value();
1566
540
    }
1567
1568
    //! Return the number of ops in the script (not counting the dynamic ones that depend on execution).
1569
    uint32_t GetStaticOps() const { return ops.count; }
1570
1571
    //! Check the ops limit of this script against the consensus limit.
1572
6.36k
    bool CheckOpsLimit() const {
1573
6.36k
        if (IsTapscript(m_script_ctx)) return true;
1574
2.04k
        if (const auto ops = GetOps()) return *ops <= MAX_OPS_PER_SCRIPT;
1575
12
        return true;
1576
2.04k
    }
miniscript::Node<CPubKey>::CheckOpsLimit() const
Line
Count
Source
1572
5.48k
    bool CheckOpsLimit() const {
1573
5.48k
        if (IsTapscript(m_script_ctx)) return true;
1574
1.50k
        if (const auto ops = GetOps()) return *ops <= MAX_OPS_PER_SCRIPT;
1575
9
        return true;
1576
1.50k
    }
miniscript::Node<unsigned int>::CheckOpsLimit() const
Line
Count
Source
1572
878
    bool CheckOpsLimit() const {
1573
878
        if (IsTapscript(m_script_ctx)) return true;
1574
540
        if (const auto ops = GetOps()) return *ops <= MAX_OPS_PER_SCRIPT;
1575
3
        return true;
1576
540
    }
1577
1578
    /** Whether this node is of type B, K or W. (That is, anything but V.) */
1579
7.15k
    bool IsBKW() const {
1580
7.15k
        return !((GetType() & "BKW"_mst) == ""_mst);
1581
7.15k
    }
miniscript::Node<CPubKey>::IsBKW() const
Line
Count
Source
1579
5.98k
    bool IsBKW() const {
1580
5.98k
        return !((GetType() & "BKW"_mst) == ""_mst);
1581
5.98k
    }
miniscript::Node<unsigned int>::IsBKW() const
Line
Count
Source
1579
1.17k
    bool IsBKW() const {
1580
1.17k
        return !((GetType() & "BKW"_mst) == ""_mst);
1581
1.17k
    }
1582
1583
    /** Return the maximum number of stack elements needed to satisfy this script non-malleably. */
1584
2.73k
    std::optional<uint32_t> GetStackSize() const {
1585
2.73k
        if (!ss.Sat().Valid()) return {};
1586
2.71k
        return ss.Sat().NetDiff() + static_cast<int32_t>(IsBKW());
1587
2.73k
    }
miniscript::Node<CPubKey>::GetStackSize() const
Line
Count
Source
1584
1.89k
    std::optional<uint32_t> GetStackSize() const {
1585
1.89k
        if (!ss.Sat().Valid()) return {};
1586
1.88k
        return ss.Sat().NetDiff() + static_cast<int32_t>(IsBKW());
1587
1.89k
    }
miniscript::Node<unsigned int>::GetStackSize() const
Line
Count
Source
1584
837
    std::optional<uint32_t> GetStackSize() const {
1585
837
        if (!ss.Sat().Valid()) return {};
1586
833
        return ss.Sat().NetDiff() + static_cast<int32_t>(IsBKW());
1587
837
    }
1588
1589
    //! Return the maximum size of the stack during execution of this script.
1590
4.44k
    std::optional<uint32_t> GetExecStackSize() const {
1591
4.44k
        if (!ss.Sat().Valid()) return {};
1592
4.43k
        return ss.Sat().Exec() + static_cast<int32_t>(IsBKW());
1593
4.44k
    }
miniscript::Node<CPubKey>::GetExecStackSize() const
Line
Count
Source
1590
4.10k
    std::optional<uint32_t> GetExecStackSize() const {
1591
4.10k
        if (!ss.Sat().Valid()) return {};
1592
4.09k
        return ss.Sat().Exec() + static_cast<int32_t>(IsBKW());
1593
4.10k
    }
miniscript::Node<unsigned int>::GetExecStackSize() const
Line
Count
Source
1590
338
    std::optional<uint32_t> GetExecStackSize() const {
1591
338
        if (!ss.Sat().Valid()) return {};
1592
338
        return ss.Sat().Exec() + static_cast<int32_t>(IsBKW());
1593
338
    }
1594
1595
    //! Check the maximum stack size for this script against the policy limit.
1596
6.36k
    bool CheckStackSize() const {
1597
        // Since in Tapscript there is no standardness limit on the script and witness sizes, we may run
1598
        // into the maximum stack size while executing the script. Make sure it doesn't happen.
1599
6.36k
        if (IsTapscript(m_script_ctx)) {
1600
4.32k
            if (const auto exec_ss = GetExecStackSize()) return exec_ss <= MAX_STACK_SIZE;
1601
9
            return true;
1602
4.32k
        }
1603
2.04k
        if (const auto ss = GetStackSize()) return *ss <= MAX_STANDARD_P2WSH_STACK_ITEMS;
1604
12
        return true;
1605
2.04k
    }
miniscript::Node<CPubKey>::CheckStackSize() const
Line
Count
Source
1596
5.48k
    bool CheckStackSize() const {
1597
        // Since in Tapscript there is no standardness limit on the script and witness sizes, we may run
1598
        // into the maximum stack size while executing the script. Make sure it doesn't happen.
1599
5.48k
        if (IsTapscript(m_script_ctx)) {
1600
3.98k
            if (const auto exec_ss = GetExecStackSize()) return exec_ss <= MAX_STACK_SIZE;
1601
9
            return true;
1602
3.98k
        }
1603
1.50k
        if (const auto ss = GetStackSize()) return *ss <= MAX_STANDARD_P2WSH_STACK_ITEMS;
1604
9
        return true;
1605
1.50k
    }
miniscript::Node<unsigned int>::CheckStackSize() const
Line
Count
Source
1596
878
    bool CheckStackSize() const {
1597
        // Since in Tapscript there is no standardness limit on the script and witness sizes, we may run
1598
        // into the maximum stack size while executing the script. Make sure it doesn't happen.
1599
878
        if (IsTapscript(m_script_ctx)) {
1600
338
            if (const auto exec_ss = GetExecStackSize()) return exec_ss <= MAX_STACK_SIZE;
1601
0
            return true;
1602
338
        }
1603
540
        if (const auto ss = GetStackSize()) return *ss <= MAX_STANDARD_P2WSH_STACK_ITEMS;
1604
3
        return true;
1605
540
    }
1606
1607
    //! Whether no satisfaction exists for this node.
1608
163
    bool IsNotSatisfiable() const { return !GetStackSize(); }
1609
1610
    /** Return the maximum size in bytes of a witness to satisfy this script non-malleably. Note this does
1611
     * not include the witness script push. */
1612
526
    std::optional<uint32_t> GetWitnessSize() const {
1613
526
        if (!ws.sat.Valid()) return {};
1614
526
        return ws.sat.Value();
1615
526
    }
miniscript::Node<CPubKey>::GetWitnessSize() const
Line
Count
Source
1612
376
    std::optional<uint32_t> GetWitnessSize() const {
1613
376
        if (!ws.sat.Valid()) return {};
1614
376
        return ws.sat.Value();
1615
376
    }
miniscript::Node<unsigned int>::GetWitnessSize() const
Line
Count
Source
1612
150
    std::optional<uint32_t> GetWitnessSize() const {
1613
150
        if (!ws.sat.Valid()) return {};
1614
150
        return ws.sat.Value();
1615
150
    }
1616
1617
    //! Return the expression type.
1618
159M
    Type GetType() const { return typ; }
miniscript::Node<CPubKey>::GetType() const
Line
Count
Source
1618
24.3M
    Type GetType() const { return typ; }
miniscript::Node<unsigned int>::GetType() const
Line
Count
Source
1618
4.13M
    Type GetType() const { return typ; }
miniscript::Node<XOnlyPubKey>::GetType() const
Line
Count
Source
1618
130M
    Type GetType() const { return typ; }
1619
1620
    //! Return the script context for this node.
1621
1.47k
    MiniscriptContext GetMsCtx() const { return m_script_ctx; }
1622
1623
    //! Find an insane subnode which has no insane children. Nullptr if there is none.
1624
15
    const Node* FindInsaneSub() const {
1625
114
        return TreeEval<const Node*>([](const Node& node, std::span<const Node*> subs) -> const Node* {
1626
114
            for (auto& sub: subs) if (sub) return sub;
1627
103
            if (!node.IsSaneSubexpression()) return &node;
1628
92
            return nullptr;
1629
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
1625
7
        return TreeEval<const Node*>([](const Node& node, std::span<const Node*> subs) -> const Node* {
1626
7
            for (auto& sub: subs) if (sub) return sub;
1627
6
            if (!node.IsSaneSubexpression()) return &node;
1628
5
            return nullptr;
1629
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
1625
107
        return TreeEval<const Node*>([](const Node& node, std::span<const Node*> subs) -> const Node* {
1626
107
            for (auto& sub: subs) if (sub) return sub;
1627
97
            if (!node.IsSaneSubexpression()) return &node;
1628
87
            return nullptr;
1629
97
        });
1630
15
    }
miniscript::Node<CPubKey>::FindInsaneSub() const
Line
Count
Source
1624
1
    const Node* FindInsaneSub() const {
1625
1
        return TreeEval<const Node*>([](const Node& node, std::span<const Node*> subs) -> const Node* {
1626
1
            for (auto& sub: subs) if (sub) return sub;
1627
1
            if (!node.IsSaneSubexpression()) return &node;
1628
1
            return nullptr;
1629
1
        });
1630
1
    }
miniscript::Node<unsigned int>::FindInsaneSub() const
Line
Count
Source
1624
14
    const Node* FindInsaneSub() const {
1625
14
        return TreeEval<const Node*>([](const Node& node, std::span<const Node*> subs) -> const Node* {
1626
14
            for (auto& sub: subs) if (sub) return sub;
1627
14
            if (!node.IsSaneSubexpression()) return &node;
1628
14
            return nullptr;
1629
14
        });
1630
14
    }
1631
1632
    //! Determine whether a Miniscript node is satisfiable. fn(node) will be invoked for all
1633
    //! key, time, and hashing nodes, and should return their satisfiability.
1634
    template<typename F>
1635
    bool IsSatisfiable(F fn) const
1636
375
    {
1637
        // TreeEval() doesn't support bool as NodeType, so use int instead.
1638
25.4k
        return TreeEval<int>([&fn](const Node& node, std::span<int> subs) -> bool {
1639
25.4k
            switch (node.fragment) {
1640
249
                case Fragment::JUST_0:
1641
249
                    return false;
1642
231
                case Fragment::JUST_1:
1643
231
                    return true;
1644
1.36k
                case Fragment::PK_K:
1645
1.44k
                case Fragment::PK_H:
1646
1.47k
                case Fragment::MULTI:
1647
1.48k
                case Fragment::MULTI_A:
1648
1.67k
                case Fragment::AFTER:
1649
7.79k
                case Fragment::OLDER:
1650
7.83k
                case Fragment::HASH256:
1651
7.85k
                case Fragment::HASH160:
1652
7.91k
                case Fragment::SHA256:
1653
7.93k
                case Fragment::RIPEMD160:
1654
7.93k
                    return bool{fn(node)};
1655
87
                case Fragment::ANDOR:
1656
87
                    return (subs[0] && subs[1]) || subs[2];
1657
198
                case Fragment::AND_V:
1658
7.45k
                case Fragment::AND_B:
1659
7.45k
                    return subs[0] && subs[1];
1660
24
                case Fragment::OR_B:
1661
42
                case Fragment::OR_C:
1662
87
                case Fragment::OR_D:
1663
324
                case Fragment::OR_I:
1664
324
                    return subs[0] || subs[1];
1665
48
                case Fragment::THRESH:
1666
48
                    return static_cast<uint32_t>(std::count(subs.begin(), subs.end(), true)) >= node.k;
1667
9.08k
                default: // wrappers
1668
9.08k
                    assert(subs.size() >= 1);
1669
9.08k
                    CHECK_NONFATAL(subs.size() == 1);
1670
9.08k
                    return subs[0];
1671
25.4k
            }
1672
25.4k
        });
1673
375
    }
1674
1675
    //! Check whether this node is valid at all.
1676
7.96M
    bool IsValid() const {
1677
7.96M
        if (GetType() == ""_mst) return false;
1678
7.96M
        return ScriptSize() <= internal::MaxScriptSize(m_script_ctx);
1679
7.96M
    }
miniscript::Node<CPubKey>::IsValid() const
Line
Count
Source
1676
31.2k
    bool IsValid() const {
1677
31.2k
        if (GetType() == ""_mst) return false;
1678
31.2k
        return ScriptSize() <= internal::MaxScriptSize(m_script_ctx);
1679
31.2k
    }
miniscript::Node<unsigned int>::IsValid() const
Line
Count
Source
1676
673k
    bool IsValid() const {
1677
673k
        if (GetType() == ""_mst) return false;
1678
673k
        return ScriptSize() <= internal::MaxScriptSize(m_script_ctx);
1679
673k
    }
miniscript::Node<XOnlyPubKey>::IsValid() const
Line
Count
Source
1676
7.26M
    bool IsValid() const {
1677
7.26M
        if (GetType() == ""_mst) return false;
1678
7.26M
        return ScriptSize() <= internal::MaxScriptSize(m_script_ctx);
1679
7.26M
    }
1680
1681
    //! Check whether this node is valid as a script on its own.
1682
10.2k
    bool IsValidTopLevel() const { return IsValid() && GetType() << "B"_mst; }
miniscript::Node<CPubKey>::IsValidTopLevel() const
Line
Count
Source
1682
5.68k
    bool IsValidTopLevel() const { return IsValid() && GetType() << "B"_mst; }
miniscript::Node<unsigned int>::IsValidTopLevel() const
Line
Count
Source
1682
1.39k
    bool IsValidTopLevel() const { return IsValid() && GetType() << "B"_mst; }
miniscript::Node<XOnlyPubKey>::IsValidTopLevel() const
Line
Count
Source
1682
3.16k
    bool IsValidTopLevel() const { return IsValid() && GetType() << "B"_mst; }
1683
1684
    //! Check whether this script can always be satisfied in a non-malleable way.
1685
6.20k
    bool IsNonMalleable() const { return GetType() << "m"_mst; }
miniscript::Node<CPubKey>::IsNonMalleable() const
Line
Count
Source
1685
5.31k
    bool IsNonMalleable() const { return GetType() << "m"_mst; }
miniscript::Node<unsigned int>::IsNonMalleable() const
Line
Count
Source
1685
887
    bool IsNonMalleable() const { return GetType() << "m"_mst; }
1686
1687
    //! Check whether this script always needs a signature.
1688
4.76k
    bool NeedsSignature() const { return GetType() << "s"_mst; }
miniscript::Node<CPubKey>::NeedsSignature() const
Line
Count
Source
1688
3.98k
    bool NeedsSignature() const { return GetType() << "s"_mst; }
miniscript::Node<unsigned int>::NeedsSignature() const
Line
Count
Source
1688
778
    bool NeedsSignature() const { return GetType() << "s"_mst; }
1689
1690
    //! Check whether there is no satisfaction path that contains both timelocks and heightlocks
1691
5.03k
    bool CheckTimeLocksMix() const { return GetType() << "k"_mst; }
miniscript::Node<CPubKey>::CheckTimeLocksMix() const
Line
Count
Source
1691
4.15k
    bool CheckTimeLocksMix() const { return GetType() << "k"_mst; }
miniscript::Node<unsigned int>::CheckTimeLocksMix() const
Line
Count
Source
1691
876
    bool CheckTimeLocksMix() const { return GetType() << "k"_mst; }
1692
1693
    //! Check whether there is no duplicate key across this fragment and all its sub-fragments.
1694
4.76k
    bool CheckDuplicateKey() const { return has_duplicate_keys && !*has_duplicate_keys; }
miniscript::Node<CPubKey>::CheckDuplicateKey() const
Line
Count
Source
1694
3.89k
    bool CheckDuplicateKey() const { return has_duplicate_keys && !*has_duplicate_keys; }
miniscript::Node<unsigned int>::CheckDuplicateKey() const
Line
Count
Source
1694
868
    bool CheckDuplicateKey() const { return has_duplicate_keys && !*has_duplicate_keys; }
1695
1696
    //! Whether successful non-malleable satisfactions are guaranteed to be valid.
1697
6.36k
    bool ValidSatisfactions() const { return IsValid() && CheckOpsLimit() && CheckStackSize(); }
miniscript::Node<CPubKey>::ValidSatisfactions() const
Line
Count
Source
1697
5.48k
    bool ValidSatisfactions() const { return IsValid() && CheckOpsLimit() && CheckStackSize(); }
miniscript::Node<unsigned int>::ValidSatisfactions() const
Line
Count
Source
1697
882
    bool ValidSatisfactions() const { return IsValid() && CheckOpsLimit() && CheckStackSize(); }
1698
1699
    //! Whether the apparent policy of this node matches its script semantics. Doesn't guarantee it is a safe script on its own.
1700
6.09k
    bool IsSaneSubexpression() const { return ValidSatisfactions() && IsNonMalleable() && CheckTimeLocksMix() && CheckDuplicateKey(); }
miniscript::Node<CPubKey>::IsSaneSubexpression() const
Line
Count
Source
1700
5.21k
    bool IsSaneSubexpression() const { return ValidSatisfactions() && IsNonMalleable() && CheckTimeLocksMix() && CheckDuplicateKey(); }
miniscript::Node<unsigned int>::IsSaneSubexpression() const
Line
Count
Source
1700
882
    bool IsSaneSubexpression() const { return ValidSatisfactions() && IsNonMalleable() && CheckTimeLocksMix() && CheckDuplicateKey(); }
1701
1702
    //! Check whether this node is safe as a script on its own.
1703
5.99k
    bool IsSane() const { return IsValidTopLevel() && IsSaneSubexpression() && NeedsSignature(); }
miniscript::Node<CPubKey>::IsSane() const
Line
Count
Source
1703
5.20k
    bool IsSane() const { return IsValidTopLevel() && IsSaneSubexpression() && NeedsSignature(); }
miniscript::Node<unsigned int>::IsSane() const
Line
Count
Source
1703
789
    bool IsSane() const { return IsValidTopLevel() && IsSaneSubexpression() && NeedsSignature(); }
1704
1705
    //! Produce a witness for this script, if possible and given the information available in the context.
1706
    //! The non-malleable satisfaction is guaranteed to be valid if it exists, and ValidSatisfaction()
1707
    //! is true. If IsSane() holds, this satisfaction is guaranteed to succeed in case the node's
1708
    //! conditions are satisfied (private keys and hash preimages available, locktimes satisfied).
1709
    template<typename Ctx>
1710
8.22k
    Availability Satisfy(const Ctx& ctx, std::vector<std::vector<unsigned char>>& stack, bool nonmalleable = true) const {
1711
8.22k
        auto ret = ProduceInput(ctx);
1712
8.22k
        if (nonmalleable && (ret.sat.malleable || !ret.sat.has_sig)) return Availability::NO;
1713
3.42k
        stack = std::move(ret.sat.stack);
1714
3.42k
        return ret.sat.available;
1715
8.22k
    }
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
1710
4.82k
    Availability Satisfy(const Ctx& ctx, std::vector<std::vector<unsigned char>>& stack, bool nonmalleable = true) const {
1711
4.82k
        auto ret = ProduceInput(ctx);
1712
4.82k
        if (nonmalleable && (ret.sat.malleable || !ret.sat.has_sig)) return Availability::NO;
1713
2.68k
        stack = std::move(ret.sat.stack);
1714
2.68k
        return ret.sat.available;
1715
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
1710
3.16k
    Availability Satisfy(const Ctx& ctx, std::vector<std::vector<unsigned char>>& stack, bool nonmalleable = true) const {
1711
3.16k
        auto ret = ProduceInput(ctx);
1712
3.16k
        if (nonmalleable && (ret.sat.malleable || !ret.sat.has_sig)) return Availability::NO;
1713
628
        stack = std::move(ret.sat.stack);
1714
628
        return ret.sat.available;
1715
3.16k
    }
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
1710
234
    Availability Satisfy(const Ctx& ctx, std::vector<std::vector<unsigned char>>& stack, bool nonmalleable = true) const {
1711
234
        auto ret = ProduceInput(ctx);
1712
234
        if (nonmalleable && (ret.sat.malleable || !ret.sat.has_sig)) return Availability::NO;
1713
113
        stack = std::move(ret.sat.stack);
1714
113
        return ret.sat.available;
1715
234
    }
1716
1717
    //! Equality testing.
1718
    bool operator==(const Node<Key>& arg) const { return Compare(*this, arg) == 0; }
1719
1720
    // Constructors with various argument combinations, which bypass the duplicate key check.
1721
    Node(internal::NoDupCheck, MiniscriptContext script_ctx, enum Fragment nt, std::vector<Node> sub, std::vector<unsigned char> arg, uint32_t val = 0)
1722
        : 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()) {}
1723
    Node(internal::NoDupCheck, MiniscriptContext script_ctx, enum Fragment nt, std::vector<unsigned char> arg, uint32_t val = 0)
1724
363
        : 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
1724
158
        : 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
1724
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
1724
12
        : fragment(nt), k(val), data(std::move(arg)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1725
    Node(internal::NoDupCheck, MiniscriptContext script_ctx, enum Fragment nt, std::vector<Node> sub, std::vector<Key> key, uint32_t val = 0)
1726
        : 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()) {}
1727
    Node(internal::NoDupCheck, MiniscriptContext script_ctx, enum Fragment nt, std::vector<Key> key, uint32_t val = 0)
1728
6.91k
        : 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
1728
1.86k
        : 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
1728
1.69k
        : 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
1728
3.35k
        : fragment(nt), k(val), keys(std::move(key)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1729
    Node(internal::NoDupCheck, MiniscriptContext script_ctx, enum Fragment nt, std::vector<Node> sub, uint32_t val = 0)
1730
8.46M
        : 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
1730
17.8k
        : 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
1730
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
1730
7.25M
        : fragment(nt), k(val), subs(std::move(sub)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1731
    Node(internal::NoDupCheck, MiniscriptContext script_ctx, enum Fragment nt, uint32_t val = 0)
1732
9.93k
        : 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
1732
8.67k
        : 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
1732
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
1732
488
        : fragment(nt), k(val), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1733
1734
    // Constructors with various argument combinations, which do perform the duplicate key check.
1735
    template <typename Ctx> Node(const Ctx& ctx, enum Fragment nt, std::vector<Node> sub, std::vector<unsigned char> arg, uint32_t val = 0)
1736
        : Node(internal::NoDupCheck{}, ctx.MsContext(), nt, std::move(sub), std::move(arg), val) { DuplicateKeyCheck(ctx); }
1737
    template <typename Ctx> Node(const Ctx& ctx, enum Fragment nt, std::vector<unsigned char> arg, uint32_t val = 0)
1738
        : Node(internal::NoDupCheck{}, ctx.MsContext(), nt, std::move(arg), val) { DuplicateKeyCheck(ctx);}
1739
    template <typename Ctx> Node(const Ctx& ctx, enum Fragment nt, std::vector<Node> sub, std::vector<Key> key, uint32_t val = 0)
1740
        : Node(internal::NoDupCheck{}, ctx.MsContext(), nt, std::move(sub), std::move(key), val) { DuplicateKeyCheck(ctx); }
1741
    template <typename Ctx> Node(const Ctx& ctx, enum Fragment nt, std::vector<Key> key, uint32_t val = 0)
1742
        : Node(internal::NoDupCheck{}, ctx.MsContext(), nt, std::move(key), val) { DuplicateKeyCheck(ctx); }
1743
    template <typename Ctx> Node(const Ctx& ctx, enum Fragment nt, std::vector<Node> sub, uint32_t val = 0)
1744
        : Node(internal::NoDupCheck{}, ctx.MsContext(), nt, std::move(sub), val) { DuplicateKeyCheck(ctx); }
1745
    template <typename Ctx> Node(const Ctx& ctx, enum Fragment nt, uint32_t val = 0)
1746
        : Node(internal::NoDupCheck{}, ctx.MsContext(), nt, val) { DuplicateKeyCheck(ctx); }
1747
1748
    // Delete copy constructor and assignment operator, use Clone() instead
1749
    Node(const Node&) = delete;
1750
    Node& operator=(const Node&) = delete;
1751
1752
    // subs is movable, circumventing recursion, so these are permitted.
1753
10.1M
    Node(Node&&) noexcept = default;
miniscript::Node<CPubKey>::Node(miniscript::Node<CPubKey>&&)
Line
Count
Source
1753
45.2k
    Node(Node&&) noexcept = default;
miniscript::Node<unsigned int>::Node(miniscript::Node<unsigned int>&&)
Line
Count
Source
1753
2.79M
    Node(Node&&) noexcept = default;
miniscript::Node<XOnlyPubKey>::Node(miniscript::Node<XOnlyPubKey>&&)
Line
Count
Source
1753
7.26M
    Node(Node&&) noexcept = default;
1754
8.46M
    Node& operator=(Node&&) noexcept = default;
miniscript::Node<unsigned int>::operator=(miniscript::Node<unsigned int>&&)
Line
Count
Source
1754
1.19M
    Node& operator=(Node&&) noexcept = default;
miniscript::Node<CPubKey>::operator=(miniscript::Node<CPubKey>&&)
Line
Count
Source
1754
17.0k
    Node& operator=(Node&&) noexcept = default;
miniscript::Node<XOnlyPubKey>::operator=(miniscript::Node<XOnlyPubKey>&&)
Line
Count
Source
1754
7.25M
    Node& operator=(Node&&) noexcept = default;
1755
};
1756
1757
namespace internal {
1758
1759
enum class ParseContext {
1760
    /** An expression which may be begin with wrappers followed by a colon. */
1761
    WRAPPED_EXPR,
1762
    /** A miniscript expression which does not begin with wrappers. */
1763
    EXPR,
1764
1765
    /** SWAP wraps the top constructed node with s: */
1766
    SWAP,
1767
    /** ALT wraps the top constructed node with a: */
1768
    ALT,
1769
    /** CHECK wraps the top constructed node with c: */
1770
    CHECK,
1771
    /** DUP_IF wraps the top constructed node with d: */
1772
    DUP_IF,
1773
    /** VERIFY wraps the top constructed node with v: */
1774
    VERIFY,
1775
    /** NON_ZERO wraps the top constructed node with j: */
1776
    NON_ZERO,
1777
    /** ZERO_NOTEQUAL wraps the top constructed node with n: */
1778
    ZERO_NOTEQUAL,
1779
    /** WRAP_U will construct an or_i(X,0) node from the top constructed node. */
1780
    WRAP_U,
1781
    /** WRAP_T will construct an and_v(X,1) node from the top constructed node. */
1782
    WRAP_T,
1783
1784
    /** AND_N will construct an andor(X,Y,0) node from the last two constructed nodes. */
1785
    AND_N,
1786
    /** AND_V will construct an and_v node from the last two constructed nodes. */
1787
    AND_V,
1788
    /** AND_B will construct an and_b node from the last two constructed nodes. */
1789
    AND_B,
1790
    /** ANDOR will construct an andor node from the last three constructed nodes. */
1791
    ANDOR,
1792
    /** OR_B will construct an or_b node from the last two constructed nodes. */
1793
    OR_B,
1794
    /** OR_C will construct an or_c node from the last two constructed nodes. */
1795
    OR_C,
1796
    /** OR_D will construct an or_d node from the last two constructed nodes. */
1797
    OR_D,
1798
    /** OR_I will construct an or_i node from the last two constructed nodes. */
1799
    OR_I,
1800
1801
    /** THRESH will read a wrapped expression, and then look for a COMMA. If
1802
     * no comma follows, it will construct a thresh node from the appropriate
1803
     * number of constructed children. Otherwise, it will recurse with another
1804
     * THRESH. */
1805
    THRESH,
1806
1807
    /** COMMA expects the next element to be ',' and fails if not. */
1808
    COMMA,
1809
    /** CLOSE_BRACKET expects the next element to be ')' and fails if not. */
1810
    CLOSE_BRACKET,
1811
};
1812
1813
int FindNextChar(std::span<const char> in, char m);
1814
1815
/** Parse a key expression fully contained within a fragment with the name given by 'func' */
1816
template<typename Key, typename Ctx>
1817
std::optional<Key> ParseKey(const std::string& func, std::span<const char>& in, const Ctx& ctx)
1818
1.15k
{
1819
1.15k
    std::span<const char> expr = script::Expr(in);
1820
1.15k
    if (!script::Func(func, expr)) return {};
1821
1.15k
    return ctx.FromString(expr);
1822
1.15k
}
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
1818
794
{
1819
794
    std::span<const char> expr = script::Expr(in);
1820
794
    if (!script::Func(func, expr)) return {};
1821
794
    return ctx.FromString(expr);
1822
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
1818
361
{
1819
361
    std::span<const char> expr = script::Expr(in);
1820
361
    if (!script::Func(func, expr)) return {};
1821
359
    return ctx.FromString(expr);
1822
361
}
1823
1824
/** Parse a hex string fully contained within a fragment with the name given by 'func' */
1825
template<typename Ctx>
1826
std::optional<std::vector<unsigned char>> ParseHexStr(const std::string& func, std::span<const char>& in, const size_t expected_size,
1827
                                                                         const Ctx& ctx)
1828
89
{
1829
89
    std::span<const char> expr = script::Expr(in);
1830
89
    if (!script::Func(func, expr)) return {};
1831
89
    std::string val = std::string(expr.begin(), expr.end());
1832
89
    if (!IsHex(val)) return {};
1833
89
    auto hash = ParseHex(val);
1834
89
    if (hash.size() != expected_size) return {};
1835
89
    return hash;
1836
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
1828
49
{
1829
49
    std::span<const char> expr = script::Expr(in);
1830
49
    if (!script::Func(func, expr)) return {};
1831
49
    std::string val = std::string(expr.begin(), expr.end());
1832
49
    if (!IsHex(val)) return {};
1833
49
    auto hash = ParseHex(val);
1834
49
    if (hash.size() != expected_size) return {};
1835
49
    return hash;
1836
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
1828
40
{
1829
40
    std::span<const char> expr = script::Expr(in);
1830
40
    if (!script::Func(func, expr)) return {};
1831
40
    std::string val = std::string(expr.begin(), expr.end());
1832
40
    if (!IsHex(val)) return {};
1833
40
    auto hash = ParseHex(val);
1834
40
    if (hash.size() != expected_size) return {};
1835
40
    return hash;
1836
40
}
1837
1838
/** BuildBack pops the last two elements off `constructed` and wraps them in the specified Fragment */
1839
template<typename Key>
1840
void BuildBack(const MiniscriptContext script_ctx, Fragment nt, std::vector<Node<Key>>& constructed, const bool reverse = false)
1841
9.34k
{
1842
9.34k
    Node<Key> child{std::move(constructed.back())};
1843
9.34k
    constructed.pop_back();
1844
9.34k
    if (reverse) {
1845
4.49k
        constructed.back() = Node<Key>{internal::NoDupCheck{}, script_ctx, nt, Vector(std::move(child), std::move(constructed.back()))};
1846
4.85k
    } else {
1847
4.85k
        constructed.back() = Node<Key>{internal::NoDupCheck{}, script_ctx, nt, Vector(std::move(constructed.back()), std::move(child))};
1848
4.85k
    }
1849
9.34k
}
void miniscript::internal::BuildBack<CPubKey>(miniscript::MiniscriptContext, miniscript::Fragment, std::vector<miniscript::Node<CPubKey>, std::allocator<miniscript::Node<CPubKey>>>&, bool)
Line
Count
Source
1841
7.56k
{
1842
7.56k
    Node<Key> child{std::move(constructed.back())};
1843
7.56k
    constructed.pop_back();
1844
7.56k
    if (reverse) {
1845
2.97k
        constructed.back() = Node<Key>{internal::NoDupCheck{}, script_ctx, nt, Vector(std::move(child), std::move(constructed.back()))};
1846
4.59k
    } else {
1847
4.59k
        constructed.back() = Node<Key>{internal::NoDupCheck{}, script_ctx, nt, Vector(std::move(constructed.back()), std::move(child))};
1848
4.59k
    }
1849
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
1841
1.14k
{
1842
1.14k
    Node<Key> child{std::move(constructed.back())};
1843
1.14k
    constructed.pop_back();
1844
1.14k
    if (reverse) {
1845
882
        constructed.back() = Node<Key>{internal::NoDupCheck{}, script_ctx, nt, Vector(std::move(child), std::move(constructed.back()))};
1846
882
    } else {
1847
258
        constructed.back() = Node<Key>{internal::NoDupCheck{}, script_ctx, nt, Vector(std::move(constructed.back()), std::move(child))};
1848
258
    }
1849
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
1841
640
{
1842
640
    Node<Key> child{std::move(constructed.back())};
1843
640
    constructed.pop_back();
1844
640
    if (reverse) {
1845
640
        constructed.back() = Node<Key>{internal::NoDupCheck{}, script_ctx, nt, Vector(std::move(child), std::move(constructed.back()))};
1846
640
    } else {
1847
0
        constructed.back() = Node<Key>{internal::NoDupCheck{}, script_ctx, nt, Vector(std::move(constructed.back()), std::move(child))};
1848
0
    }
1849
640
}
1850
1851
/**
1852
 * Parse a miniscript from its textual descriptor form.
1853
 * This does not check whether the script is valid, let alone sane. The caller is expected to use
1854
 * the `IsValidTopLevel()` and `IsSaneTopLevel()` to check for these properties on the node.
1855
 */
1856
template <typename Key, typename Ctx>
1857
inline std::optional<Node<Key>> Parse(std::span<const char> in, const Ctx& ctx)
1858
753
{
1859
753
    using namespace script;
1860
1861
    // Account for the minimum script size for all parsed fragments so far. It "borrows" 1
1862
    // script byte from all leaf nodes, counting it instead whenever a space for a recursive
1863
    // expression is added (through andor, and_*, or_*, thresh). This guarantees that all fragments
1864
    // increment the script_size by at least one, except for:
1865
    // - "0", "1": these leafs are only a single byte, so their subtracted-from increment is 0.
1866
    //   This is not an issue however, as "space" for them has to be created by combinators,
1867
    //   which do increment script_size.
1868
    // - "v:": the v wrapper adds nothing as in some cases it results in no opcode being added
1869
    //   (instead transforming another opcode into its VERIFY form). However, the v: wrapper has
1870
    //   to be interleaved with other fragments to be valid, so this is not a concern.
1871
753
    size_t script_size{1};
1872
753
    size_t max_size{internal::MaxScriptSize(ctx.MsContext())};
1873
1874
    // The two integers are used to hold state for thresh()
1875
753
    std::vector<std::tuple<ParseContext, int64_t, int64_t>> to_parse;
1876
753
    std::vector<Node<Key>> constructed;
1877
1878
753
    to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
1879
1880
    // Parses a multi() or multi_a() from its string representation. Returns false on parsing error.
1881
753
    const auto parse_multi_exp = [&](std::span<const char>& in, const bool is_multi_a) -> bool {
1882
59
        const auto max_keys{is_multi_a ? MAX_PUBKEYS_PER_MULTI_A : MAX_PUBKEYS_PER_MULTISIG};
1883
59
        const auto required_ctx{is_multi_a ? MiniscriptContext::TAPSCRIPT : MiniscriptContext::P2WSH};
1884
59
        if (ctx.MsContext() != required_ctx) return false;
1885
        // Get threshold
1886
47
        int next_comma = FindNextChar(in, ',');
1887
47
        if (next_comma < 1) return false;
1888
47
        const auto k_to_integral{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
1889
47
        if (!k_to_integral.has_value()) return false;
1890
46
        const int64_t k{k_to_integral.value()};
1891
46
        in = in.subspan(next_comma + 1);
1892
        // Get keys. It is compatible for both compressed and x-only keys.
1893
46
        std::vector<Key> keys;
1894
175
        while (next_comma != -1) {
1895
129
            next_comma = FindNextChar(in, ',');
1896
129
            int key_length = (next_comma == -1) ? FindNextChar(in, ')') : next_comma;
1897
129
            if (key_length < 1) return false;
1898
129
            std::span<const char> sp{in.begin(), in.begin() + key_length};
1899
129
            auto key = ctx.FromString(sp);
1900
129
            if (!key) return false;
1901
129
            keys.push_back(std::move(*key));
1902
129
            in = in.subspan(key_length + 1);
1903
129
        }
1904
46
        if (keys.size() < 1 || keys.size() > max_keys) return false;
1905
46
        if (k < 1 || k > (int64_t)keys.size()) return false;
1906
46
        if (is_multi_a) {
1907
            // (push + xonly-key + CHECKSIG[ADD]) * n + k + OP_NUMEQUAL(VERIFY), minus one.
1908
16
            script_size += (1 + 32 + 1) * keys.size() + BuildScript(k).size();
1909
16
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), k);
1910
30
        } else {
1911
30
            script_size += 2 + (keys.size() > 16) + (k > 16) + 34 * keys.size();
1912
30
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), k);
1913
30
        }
1914
46
        return true;
1915
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
1881
27
    const auto parse_multi_exp = [&](std::span<const char>& in, const bool is_multi_a) -> bool {
1882
27
        const auto max_keys{is_multi_a ? MAX_PUBKEYS_PER_MULTI_A : MAX_PUBKEYS_PER_MULTISIG};
1883
27
        const auto required_ctx{is_multi_a ? MiniscriptContext::TAPSCRIPT : MiniscriptContext::P2WSH};
1884
27
        if (ctx.MsContext() != required_ctx) return false;
1885
        // Get threshold
1886
16
        int next_comma = FindNextChar(in, ',');
1887
16
        if (next_comma < 1) return false;
1888
16
        const auto k_to_integral{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
1889
16
        if (!k_to_integral.has_value()) return false;
1890
15
        const int64_t k{k_to_integral.value()};
1891
15
        in = in.subspan(next_comma + 1);
1892
        // Get keys. It is compatible for both compressed and x-only keys.
1893
15
        std::vector<Key> keys;
1894
64
        while (next_comma != -1) {
1895
49
            next_comma = FindNextChar(in, ',');
1896
49
            int key_length = (next_comma == -1) ? FindNextChar(in, ')') : next_comma;
1897
49
            if (key_length < 1) return false;
1898
49
            std::span<const char> sp{in.begin(), in.begin() + key_length};
1899
49
            auto key = ctx.FromString(sp);
1900
49
            if (!key) return false;
1901
49
            keys.push_back(std::move(*key));
1902
49
            in = in.subspan(key_length + 1);
1903
49
        }
1904
15
        if (keys.size() < 1 || keys.size() > max_keys) return false;
1905
15
        if (k < 1 || k > (int64_t)keys.size()) return false;
1906
15
        if (is_multi_a) {
1907
            // (push + xonly-key + CHECKSIG[ADD]) * n + k + OP_NUMEQUAL(VERIFY), minus one.
1908
2
            script_size += (1 + 32 + 1) * keys.size() + BuildScript(k).size();
1909
2
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), k);
1910
13
        } else {
1911
13
            script_size += 2 + (keys.size() > 16) + (k > 16) + 34 * keys.size();
1912
13
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), k);
1913
13
        }
1914
15
        return true;
1915
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
1881
32
    const auto parse_multi_exp = [&](std::span<const char>& in, const bool is_multi_a) -> bool {
1882
32
        const auto max_keys{is_multi_a ? MAX_PUBKEYS_PER_MULTI_A : MAX_PUBKEYS_PER_MULTISIG};
1883
32
        const auto required_ctx{is_multi_a ? MiniscriptContext::TAPSCRIPT : MiniscriptContext::P2WSH};
1884
32
        if (ctx.MsContext() != required_ctx) return false;
1885
        // Get threshold
1886
31
        int next_comma = FindNextChar(in, ',');
1887
31
        if (next_comma < 1) return false;
1888
31
        const auto k_to_integral{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
1889
31
        if (!k_to_integral.has_value()) return false;
1890
31
        const int64_t k{k_to_integral.value()};
1891
31
        in = in.subspan(next_comma + 1);
1892
        // Get keys. It is compatible for both compressed and x-only keys.
1893
31
        std::vector<Key> keys;
1894
111
        while (next_comma != -1) {
1895
80
            next_comma = FindNextChar(in, ',');
1896
80
            int key_length = (next_comma == -1) ? FindNextChar(in, ')') : next_comma;
1897
80
            if (key_length < 1) return false;
1898
80
            std::span<const char> sp{in.begin(), in.begin() + key_length};
1899
80
            auto key = ctx.FromString(sp);
1900
80
            if (!key) return false;
1901
80
            keys.push_back(std::move(*key));
1902
80
            in = in.subspan(key_length + 1);
1903
80
        }
1904
31
        if (keys.size() < 1 || keys.size() > max_keys) return false;
1905
31
        if (k < 1 || k > (int64_t)keys.size()) return false;
1906
31
        if (is_multi_a) {
1907
            // (push + xonly-key + CHECKSIG[ADD]) * n + k + OP_NUMEQUAL(VERIFY), minus one.
1908
14
            script_size += (1 + 32 + 1) * keys.size() + BuildScript(k).size();
1909
14
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), k);
1910
17
        } else {
1911
17
            script_size += 2 + (keys.size() > 16) + (k > 16) + 34 * keys.size();
1912
17
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), k);
1913
17
        }
1914
31
        return true;
1915
31
    };
1916
1917
379k
    while (!to_parse.empty()) {
1918
379k
        if (script_size > max_size) return {};
1919
1920
        // Get the current context we are decoding within
1921
379k
        auto [cur_context, n, k] = to_parse.back();
1922
379k
        to_parse.pop_back();
1923
1924
379k
        switch (cur_context) {
1925
14.1k
        case ParseContext::WRAPPED_EXPR: {
1926
14.1k
            std::optional<size_t> colon_index{};
1927
698k
            for (size_t i = 1; i < in.size(); ++i) {
1928
698k
                if (in[i] == ':') {
1929
6.73k
                    colon_index = i;
1930
6.73k
                    break;
1931
6.73k
                }
1932
691k
                if (in[i] < 'a' || in[i] > 'z') break;
1933
691k
            }
1934
            // If there is no colon, this loop won't execute
1935
14.1k
            bool last_was_v{false};
1936
679k
            for (size_t j = 0; colon_index && j < *colon_index; ++j) {
1937
665k
                if (script_size > max_size) return {};
1938
665k
                if (in[j] == 'a') {
1939
6.28k
                    script_size += 2;
1940
6.28k
                    to_parse.emplace_back(ParseContext::ALT, -1, -1);
1941
659k
                } else if (in[j] == 's') {
1942
72
                    script_size += 1;
1943
72
                    to_parse.emplace_back(ParseContext::SWAP, -1, -1);
1944
659k
                } else if (in[j] == 'c') {
1945
72
                    script_size += 1;
1946
72
                    to_parse.emplace_back(ParseContext::CHECK, -1, -1);
1947
659k
                } else if (in[j] == 'd') {
1948
18
                    script_size += 3;
1949
18
                    to_parse.emplace_back(ParseContext::DUP_IF, -1, -1);
1950
659k
                } else if (in[j] == 'j') {
1951
10
                    script_size += 4;
1952
10
                    to_parse.emplace_back(ParseContext::NON_ZERO, -1, -1);
1953
659k
                } else if (in[j] == 'n') {
1954
658k
                    script_size += 1;
1955
658k
                    to_parse.emplace_back(ParseContext::ZERO_NOTEQUAL, -1, -1);
1956
658k
                } else if (in[j] == 'v') {
1957
                    // do not permit "...vv...:"; it's not valid, and also doesn't trigger early
1958
                    // failure as script_size isn't incremented.
1959
261
                    if (last_was_v) return {};
1960
261
                    to_parse.emplace_back(ParseContext::VERIFY, -1, -1);
1961
261
                } else if (in[j] == 'u') {
1962
23
                    script_size += 4;
1963
23
                    to_parse.emplace_back(ParseContext::WRAP_U, -1, -1);
1964
105
                } else if (in[j] == 't') {
1965
46
                    script_size += 1;
1966
46
                    to_parse.emplace_back(ParseContext::WRAP_T, -1, -1);
1967
59
                } else if (in[j] == 'l') {
1968
                    // The l: wrapper is equivalent to or_i(0,X)
1969
59
                    script_size += 4;
1970
59
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
1971
59
                    to_parse.emplace_back(ParseContext::OR_I, -1, -1);
1972
59
                } else {
1973
0
                    return {};
1974
0
                }
1975
665k
                last_was_v = (in[j] == 'v');
1976
665k
            }
1977
14.1k
            to_parse.emplace_back(ParseContext::EXPR, -1, -1);
1978
14.1k
            if (colon_index) in = in.subspan(*colon_index + 1);
1979
14.1k
            break;
1980
14.1k
        }
1981
14.1k
        case ParseContext::EXPR: {
1982
14.1k
            if (Const("0", in)) {
1983
59
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
1984
14.1k
            } else if (Const("1", in)) {
1985
115
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1);
1986
14.0k
            } else if (Const("pk(", in, /*skip=*/false)) {
1987
966
                std::optional<Key> key = ParseKey<Key, Ctx>("pk", in, ctx);
1988
966
                if (!key) return {};
1989
964
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(Node<Key>(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_K, Vector(std::move(*key)))));
1990
964
                script_size += IsTapscript(ctx.MsContext()) ? 33 : 34;
1991
13.0k
            } else if (Const("pkh(", in, /*skip=*/false)) {
1992
85
                std::optional<Key> key = ParseKey<Key, Ctx>("pkh", in, ctx);
1993
85
                if (!key) return {};
1994
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)))));
1995
85
                script_size += 24;
1996
12.9k
            } else if (Const("pk_k(", in, /*skip=*/false)) {
1997
76
                std::optional<Key> key = ParseKey<Key, Ctx>("pk_k", in, ctx);
1998
76
                if (!key) return {};
1999
74
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_K, Vector(std::move(*key)));
2000
74
                script_size += IsTapscript(ctx.MsContext()) ? 32 : 33;
2001
12.8k
            } else if (Const("pk_h(", in, /*skip=*/false)) {
2002
28
                std::optional<Key> key = ParseKey<Key, Ctx>("pk_h", in, ctx);
2003
28
                if (!key) return {};
2004
28
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_H, Vector(std::move(*key)));
2005
28
                script_size += 23;
2006
12.8k
            } else if (Const("sha256(", in, /*skip=*/false)) {
2007
30
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("sha256", in, 32, ctx);
2008
30
                if (!hash) return {};
2009
30
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, std::move(*hash));
2010
30
                script_size += 38;
2011
12.8k
            } else if (Const("ripemd160(", in, /*skip=*/false)) {
2012
15
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("ripemd160", in, 20, ctx);
2013
15
                if (!hash) return {};
2014
15
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::RIPEMD160, std::move(*hash));
2015
15
                script_size += 26;
2016
12.8k
            } else if (Const("hash256(", in, /*skip=*/false)) {
2017
22
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("hash256", in, 32, ctx);
2018
22
                if (!hash) return {};
2019
22
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, std::move(*hash));
2020
22
                script_size += 38;
2021
12.7k
            } else if (Const("hash160(", in, /*skip=*/false)) {
2022
22
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("hash160", in, 20, ctx);
2023
22
                if (!hash) return {};
2024
22
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, std::move(*hash));
2025
22
                script_size += 26;
2026
12.7k
            } else if (Const("after(", in, /*skip=*/false)) {
2027
128
                auto expr = Expr(in);
2028
128
                if (!Func("after", expr)) return {};
2029
128
                const auto num{ToIntegral<int64_t>(std::string_view(expr.begin(), expr.end()))};
2030
128
                if (!num.has_value() || *num < 1 || *num >= 0x80000000L) return {};
2031
122
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num);
2032
122
                script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
2033
12.6k
            } else if (Const("older(", in, /*skip=*/false)) {
2034
5.55k
                auto expr = Expr(in);
2035
5.55k
                if (!Func("older", expr)) return {};
2036
5.55k
                const auto num{ToIntegral<int64_t>(std::string_view(expr.begin(), expr.end()))};
2037
5.55k
                if (!num.has_value() || *num < 1 || *num >= 0x80000000L) return {};
2038
5.55k
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num);
2039
5.55k
                script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
2040
7.07k
            } else if (Const("multi(", in)) {
2041
41
                if (!parse_multi_exp(in, /* is_multi_a = */false)) return {};
2042
7.03k
            } else if (Const("multi_a(", in)) {
2043
18
                if (!parse_multi_exp(in, /* is_multi_a = */true)) return {};
2044
7.01k
            } else if (Const("thresh(", in)) {
2045
58
                int next_comma = FindNextChar(in, ',');
2046
58
                if (next_comma < 1) return {};
2047
58
                const auto k{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
2048
58
                if (!k.has_value() || *k < 1) return {};
2049
55
                in = in.subspan(next_comma + 1);
2050
                // n = 1 here because we read the first WRAPPED_EXPR before reaching THRESH
2051
55
                to_parse.emplace_back(ParseContext::THRESH, 1, *k);
2052
55
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2053
55
                script_size += 2 + (*k > 16) + (*k > 0x7f) + (*k > 0x7fff) + (*k > 0x7fffff);
2054
6.95k
            } else if (Const("andor(", in)) {
2055
55
                to_parse.emplace_back(ParseContext::ANDOR, -1, -1);
2056
55
                to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
2057
55
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2058
55
                to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2059
55
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2060
55
                to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2061
55
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2062
55
                script_size += 5;
2063
6.90k
            } else {
2064
6.90k
                if (Const("and_n(", in)) {
2065
16
                    to_parse.emplace_back(ParseContext::AND_N, -1, -1);
2066
16
                    script_size += 5;
2067
6.88k
                } else if (Const("and_b(", in)) {
2068
6.19k
                    to_parse.emplace_back(ParseContext::AND_B, -1, -1);
2069
6.19k
                    script_size += 2;
2070
6.19k
                } else if (Const("and_v(", in)) {
2071
185
                    to_parse.emplace_back(ParseContext::AND_V, -1, -1);
2072
185
                    script_size += 1;
2073
505
                } else if (Const("or_b(", in)) {
2074
45
                    to_parse.emplace_back(ParseContext::OR_B, -1, -1);
2075
45
                    script_size += 2;
2076
460
                } else if (Const("or_c(", in)) {
2077
28
                    to_parse.emplace_back(ParseContext::OR_C, -1, -1);
2078
28
                    script_size += 3;
2079
432
                } else if (Const("or_d(", in)) {
2080
42
                    to_parse.emplace_back(ParseContext::OR_D, -1, -1);
2081
42
                    script_size += 4;
2082
390
                } else if (Const("or_i(", in)) {
2083
45
                    to_parse.emplace_back(ParseContext::OR_I, -1, -1);
2084
45
                    script_size += 4;
2085
345
                } else {
2086
345
                    return {};
2087
345
                }
2088
6.55k
                to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
2089
6.55k
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2090
6.55k
                to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2091
6.55k
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2092
6.55k
            }
2093
13.7k
            break;
2094
14.1k
        }
2095
13.7k
        case ParseContext::ALT: {
2096
4.56k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A, Vector(std::move(constructed.back()))};
2097
4.56k
            break;
2098
14.1k
        }
2099
72
        case ParseContext::SWAP: {
2100
72
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S, Vector(std::move(constructed.back()))};
2101
72
            break;
2102
14.1k
        }
2103
68
        case ParseContext::CHECK: {
2104
68
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(std::move(constructed.back()))};
2105
68
            break;
2106
14.1k
        }
2107
18
        case ParseContext::DUP_IF: {
2108
18
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D, Vector(std::move(constructed.back()))};
2109
18
            break;
2110
14.1k
        }
2111
8
        case ParseContext::NON_ZERO: {
2112
8
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J, Vector(std::move(constructed.back()))};
2113
8
            break;
2114
14.1k
        }
2115
329k
        case ParseContext::ZERO_NOTEQUAL: {
2116
329k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N, Vector(std::move(constructed.back()))};
2117
329k
            break;
2118
14.1k
        }
2119
255
        case ParseContext::VERIFY: {
2120
255
            script_size += (constructed.back().GetType() << "x"_mst);
2121
255
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V, Vector(std::move(constructed.back()))};
2122
255
            break;
2123
14.1k
        }
2124
16
        case ParseContext::WRAP_U: {
2125
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})};
2126
16
            break;
2127
14.1k
        }
2128
45
        case ParseContext::WRAP_T: {
2129
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})};
2130
45
            break;
2131
14.1k
        }
2132
4.46k
        case ParseContext::AND_B: {
2133
4.46k
            BuildBack(ctx.MsContext(), Fragment::AND_B, constructed);
2134
4.46k
            break;
2135
14.1k
        }
2136
16
        case ParseContext::AND_N: {
2137
16
            auto mid = std::move(constructed.back());
2138
16
            constructed.pop_back();
2139
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})};
2140
16
            break;
2141
14.1k
        }
2142
176
        case ParseContext::AND_V: {
2143
176
            BuildBack(ctx.MsContext(), Fragment::AND_V, constructed);
2144
176
            break;
2145
14.1k
        }
2146
44
        case ParseContext::OR_B: {
2147
44
            BuildBack(ctx.MsContext(), Fragment::OR_B, constructed);
2148
44
            break;
2149
14.1k
        }
2150
26
        case ParseContext::OR_C: {
2151
26
            BuildBack(ctx.MsContext(), Fragment::OR_C, constructed);
2152
26
            break;
2153
14.1k
        }
2154
41
        case ParseContext::OR_D: {
2155
41
            BuildBack(ctx.MsContext(), Fragment::OR_D, constructed);
2156
41
            break;
2157
14.1k
        }
2158
99
        case ParseContext::OR_I: {
2159
99
            BuildBack(ctx.MsContext(), Fragment::OR_I, constructed);
2160
99
            break;
2161
14.1k
        }
2162
52
        case ParseContext::ANDOR: {
2163
52
            auto right = std::move(constructed.back());
2164
52
            constructed.pop_back();
2165
52
            auto mid = std::move(constructed.back());
2166
52
            constructed.pop_back();
2167
52
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR, Vector(std::move(constructed.back()), std::move(mid), std::move(right))};
2168
52
            break;
2169
14.1k
        }
2170
164
        case ParseContext::THRESH: {
2171
164
            if (in.size() < 1) return {};
2172
164
            if (in[0] == ',') {
2173
110
                in = in.subspan(1);
2174
110
                to_parse.emplace_back(ParseContext::THRESH, n+1, k);
2175
110
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2176
110
                script_size += 2;
2177
110
            } else if (in[0] == ')') {
2178
54
                if (k > n) return {};
2179
52
                in = in.subspan(1);
2180
                // Children are constructed in reverse order, so iterate from end to beginning
2181
52
                std::vector<Node<Key>> subs;
2182
212
                for (int i = 0; i < n; ++i) {
2183
160
                    subs.push_back(std::move(constructed.back()));
2184
160
                    constructed.pop_back();
2185
160
                }
2186
52
                std::reverse(subs.begin(), subs.end());
2187
52
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs), k);
2188
52
            } else {
2189
0
                return {};
2190
0
            }
2191
162
            break;
2192
164
        }
2193
6.64k
        case ParseContext::COMMA: {
2194
6.64k
            if (in.size() < 1 || in[0] != ',') return {};
2195
6.64k
            in = in.subspan(1);
2196
6.64k
            break;
2197
6.64k
        }
2198
4.86k
        case ParseContext::CLOSE_BRACKET: {
2199
4.86k
            if (in.size() < 1 || in[0] != ')') return {};
2200
4.86k
            in = in.subspan(1);
2201
4.86k
            break;
2202
4.86k
        }
2203
379k
        }
2204
379k
    }
2205
2206
    // Sanity checks on the produced miniscript
2207
753
    assert(constructed.size() >= 1);
2208
370
    CHECK_NONFATAL(constructed.size() == 1);
2209
370
    assert(constructed[0].ScriptSize() == script_size);
2210
370
    if (in.size() > 0) return {};
2211
367
    Node<Key> tl_node{std::move(constructed.front())};
2212
367
    tl_node.DuplicateKeyCheck(ctx);
2213
367
    return tl_node;
2214
370
}
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
1858
220
{
1859
220
    using namespace script;
1860
1861
    // Account for the minimum script size for all parsed fragments so far. It "borrows" 1
1862
    // script byte from all leaf nodes, counting it instead whenever a space for a recursive
1863
    // expression is added (through andor, and_*, or_*, thresh). This guarantees that all fragments
1864
    // increment the script_size by at least one, except for:
1865
    // - "0", "1": these leafs are only a single byte, so their subtracted-from increment is 0.
1866
    //   This is not an issue however, as "space" for them has to be created by combinators,
1867
    //   which do increment script_size.
1868
    // - "v:": the v wrapper adds nothing as in some cases it results in no opcode being added
1869
    //   (instead transforming another opcode into its VERIFY form). However, the v: wrapper has
1870
    //   to be interleaved with other fragments to be valid, so this is not a concern.
1871
220
    size_t script_size{1};
1872
220
    size_t max_size{internal::MaxScriptSize(ctx.MsContext())};
1873
1874
    // The two integers are used to hold state for thresh()
1875
220
    std::vector<std::tuple<ParseContext, int64_t, int64_t>> to_parse;
1876
220
    std::vector<Node<Key>> constructed;
1877
1878
220
    to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
1879
1880
    // Parses a multi() or multi_a() from its string representation. Returns false on parsing error.
1881
220
    const auto parse_multi_exp = [&](std::span<const char>& in, const bool is_multi_a) -> bool {
1882
220
        const auto max_keys{is_multi_a ? MAX_PUBKEYS_PER_MULTI_A : MAX_PUBKEYS_PER_MULTISIG};
1883
220
        const auto required_ctx{is_multi_a ? MiniscriptContext::TAPSCRIPT : MiniscriptContext::P2WSH};
1884
220
        if (ctx.MsContext() != required_ctx) return false;
1885
        // Get threshold
1886
220
        int next_comma = FindNextChar(in, ',');
1887
220
        if (next_comma < 1) return false;
1888
220
        const auto k_to_integral{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
1889
220
        if (!k_to_integral.has_value()) return false;
1890
220
        const int64_t k{k_to_integral.value()};
1891
220
        in = in.subspan(next_comma + 1);
1892
        // Get keys. It is compatible for both compressed and x-only keys.
1893
220
        std::vector<Key> keys;
1894
220
        while (next_comma != -1) {
1895
220
            next_comma = FindNextChar(in, ',');
1896
220
            int key_length = (next_comma == -1) ? FindNextChar(in, ')') : next_comma;
1897
220
            if (key_length < 1) return false;
1898
220
            std::span<const char> sp{in.begin(), in.begin() + key_length};
1899
220
            auto key = ctx.FromString(sp);
1900
220
            if (!key) return false;
1901
220
            keys.push_back(std::move(*key));
1902
220
            in = in.subspan(key_length + 1);
1903
220
        }
1904
220
        if (keys.size() < 1 || keys.size() > max_keys) return false;
1905
220
        if (k < 1 || k > (int64_t)keys.size()) return false;
1906
220
        if (is_multi_a) {
1907
            // (push + xonly-key + CHECKSIG[ADD]) * n + k + OP_NUMEQUAL(VERIFY), minus one.
1908
220
            script_size += (1 + 32 + 1) * keys.size() + BuildScript(k).size();
1909
220
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), k);
1910
220
        } else {
1911
220
            script_size += 2 + (keys.size() > 16) + (k > 16) + 34 * keys.size();
1912
220
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), k);
1913
220
        }
1914
220
        return true;
1915
220
    };
1916
1917
46.4k
    while (!to_parse.empty()) {
1918
46.2k
        if (script_size > max_size) return {};
1919
1920
        // Get the current context we are decoding within
1921
46.2k
        auto [cur_context, n, k] = to_parse.back();
1922
46.2k
        to_parse.pop_back();
1923
1924
46.2k
        switch (cur_context) {
1925
12.9k
        case ParseContext::WRAPPED_EXPR: {
1926
12.9k
            std::optional<size_t> colon_index{};
1927
36.2k
            for (size_t i = 1; i < in.size(); ++i) {
1928
36.2k
                if (in[i] == ':') {
1929
6.42k
                    colon_index = i;
1930
6.42k
                    break;
1931
6.42k
                }
1932
29.8k
                if (in[i] < 'a' || in[i] > 'z') break;
1933
29.8k
            }
1934
            // If there is no colon, this loop won't execute
1935
12.9k
            bool last_was_v{false};
1936
19.4k
            for (size_t j = 0; colon_index && j < *colon_index; ++j) {
1937
6.52k
                if (script_size > max_size) return {};
1938
6.52k
                if (in[j] == 'a') {
1939
6.20k
                    script_size += 2;
1940
6.20k
                    to_parse.emplace_back(ParseContext::ALT, -1, -1);
1941
6.20k
                } else if (in[j] == 's') {
1942
21
                    script_size += 1;
1943
21
                    to_parse.emplace_back(ParseContext::SWAP, -1, -1);
1944
303
                } else if (in[j] == 'c') {
1945
56
                    script_size += 1;
1946
56
                    to_parse.emplace_back(ParseContext::CHECK, -1, -1);
1947
247
                } else if (in[j] == 'd') {
1948
8
                    script_size += 3;
1949
8
                    to_parse.emplace_back(ParseContext::DUP_IF, -1, -1);
1950
239
                } else if (in[j] == 'j') {
1951
10
                    script_size += 4;
1952
10
                    to_parse.emplace_back(ParseContext::NON_ZERO, -1, -1);
1953
229
                } else if (in[j] == 'n') {
1954
16
                    script_size += 1;
1955
16
                    to_parse.emplace_back(ParseContext::ZERO_NOTEQUAL, -1, -1);
1956
213
                } else if (in[j] == 'v') {
1957
                    // do not permit "...vv...:"; it's not valid, and also doesn't trigger early
1958
                    // failure as script_size isn't incremented.
1959
103
                    if (last_was_v) return {};
1960
103
                    to_parse.emplace_back(ParseContext::VERIFY, -1, -1);
1961
110
                } else if (in[j] == 'u') {
1962
23
                    script_size += 4;
1963
23
                    to_parse.emplace_back(ParseContext::WRAP_U, -1, -1);
1964
87
                } else if (in[j] == 't') {
1965
44
                    script_size += 1;
1966
44
                    to_parse.emplace_back(ParseContext::WRAP_T, -1, -1);
1967
44
                } else if (in[j] == 'l') {
1968
                    // The l: wrapper is equivalent to or_i(0,X)
1969
43
                    script_size += 4;
1970
43
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
1971
43
                    to_parse.emplace_back(ParseContext::OR_I, -1, -1);
1972
43
                } else {
1973
0
                    return {};
1974
0
                }
1975
6.52k
                last_was_v = (in[j] == 'v');
1976
6.52k
            }
1977
12.9k
            to_parse.emplace_back(ParseContext::EXPR, -1, -1);
1978
12.9k
            if (colon_index) in = in.subspan(*colon_index + 1);
1979
12.9k
            break;
1980
12.9k
        }
1981
12.9k
        case ParseContext::EXPR: {
1982
12.9k
            if (Const("0", in)) {
1983
56
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
1984
12.9k
            } else if (Const("1", in)) {
1985
112
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1);
1986
12.7k
            } else if (Const("pk(", in, /*skip=*/false)) {
1987
715
                std::optional<Key> key = ParseKey<Key, Ctx>("pk", in, ctx);
1988
715
                if (!key) return {};
1989
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)))));
1990
715
                script_size += IsTapscript(ctx.MsContext()) ? 33 : 34;
1991
12.0k
            } else if (Const("pkh(", in, /*skip=*/false)) {
1992
3
                std::optional<Key> key = ParseKey<Key, Ctx>("pkh", in, ctx);
1993
3
                if (!key) return {};
1994
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)))));
1995
3
                script_size += 24;
1996
12.0k
            } else if (Const("pk_k(", in, /*skip=*/false)) {
1997
51
                std::optional<Key> key = ParseKey<Key, Ctx>("pk_k", in, ctx);
1998
51
                if (!key) return {};
1999
51
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_K, Vector(std::move(*key)));
2000
51
                script_size += IsTapscript(ctx.MsContext()) ? 32 : 33;
2001
12.0k
            } else if (Const("pk_h(", in, /*skip=*/false)) {
2002
25
                std::optional<Key> key = ParseKey<Key, Ctx>("pk_h", in, ctx);
2003
25
                if (!key) return {};
2004
25
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_H, Vector(std::move(*key)));
2005
25
                script_size += 23;
2006
11.9k
            } else if (Const("sha256(", in, /*skip=*/false)) {
2007
22
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("sha256", in, 32, ctx);
2008
22
                if (!hash) return {};
2009
22
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, std::move(*hash));
2010
22
                script_size += 38;
2011
11.9k
            } else if (Const("ripemd160(", in, /*skip=*/false)) {
2012
7
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("ripemd160", in, 20, ctx);
2013
7
                if (!hash) return {};
2014
7
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::RIPEMD160, std::move(*hash));
2015
7
                script_size += 26;
2016
11.9k
            } else if (Const("hash256(", in, /*skip=*/false)) {
2017
14
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("hash256", in, 32, ctx);
2018
14
                if (!hash) return {};
2019
14
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, std::move(*hash));
2020
14
                script_size += 38;
2021
11.9k
            } else if (Const("hash160(", in, /*skip=*/false)) {
2022
6
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("hash160", in, 20, ctx);
2023
6
                if (!hash) return {};
2024
6
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, std::move(*hash));
2025
6
                script_size += 26;
2026
11.9k
            } else if (Const("after(", in, /*skip=*/false)) {
2027
79
                auto expr = Expr(in);
2028
79
                if (!Func("after", expr)) return {};
2029
79
                const auto num{ToIntegral<int64_t>(std::string_view(expr.begin(), expr.end()))};
2030
79
                if (!num.has_value() || *num < 1 || *num >= 0x80000000L) return {};
2031
73
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num);
2032
73
                script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
2033
11.8k
            } else if (Const("older(", in, /*skip=*/false)) {
2034
5.48k
                auto expr = Expr(in);
2035
5.48k
                if (!Func("older", expr)) return {};
2036
5.48k
                const auto num{ToIntegral<int64_t>(std::string_view(expr.begin(), expr.end()))};
2037
5.48k
                if (!num.has_value() || *num < 1 || *num >= 0x80000000L) return {};
2038
5.47k
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num);
2039
5.47k
                script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
2040
6.38k
            } else if (Const("multi(", in)) {
2041
23
                if (!parse_multi_exp(in, /* is_multi_a = */false)) return {};
2042
6.36k
            } else if (Const("multi_a(", in)) {
2043
4
                if (!parse_multi_exp(in, /* is_multi_a = */true)) return {};
2044
6.35k
            } else if (Const("thresh(", in)) {
2045
25
                int next_comma = FindNextChar(in, ',');
2046
25
                if (next_comma < 1) return {};
2047
25
                const auto k{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
2048
25
                if (!k.has_value() || *k < 1) return {};
2049
22
                in = in.subspan(next_comma + 1);
2050
                // n = 1 here because we read the first WRAPPED_EXPR before reaching THRESH
2051
22
                to_parse.emplace_back(ParseContext::THRESH, 1, *k);
2052
22
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2053
22
                script_size += 2 + (*k > 16) + (*k > 0x7f) + (*k > 0x7fff) + (*k > 0x7fffff);
2054
6.33k
            } else if (Const("andor(", in)) {
2055
30
                to_parse.emplace_back(ParseContext::ANDOR, -1, -1);
2056
30
                to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
2057
30
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2058
30
                to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2059
30
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2060
30
                to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2061
30
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2062
30
                script_size += 5;
2063
6.30k
            } else {
2064
6.30k
                if (Const("and_n(", in)) {
2065
8
                    to_parse.emplace_back(ParseContext::AND_N, -1, -1);
2066
8
                    script_size += 5;
2067
6.29k
                } else if (Const("and_b(", in)) {
2068
6.15k
                    to_parse.emplace_back(ParseContext::AND_B, -1, -1);
2069
6.15k
                    script_size += 2;
2070
6.15k
                } else if (Const("and_v(", in)) {
2071
43
                    to_parse.emplace_back(ParseContext::AND_V, -1, -1);
2072
43
                    script_size += 1;
2073
97
                } else if (Const("or_b(", in)) {
2074
22
                    to_parse.emplace_back(ParseContext::OR_B, -1, -1);
2075
22
                    script_size += 2;
2076
75
                } else if (Const("or_c(", in)) {
2077
16
                    to_parse.emplace_back(ParseContext::OR_C, -1, -1);
2078
16
                    script_size += 3;
2079
59
                } else if (Const("or_d(", in)) {
2080
24
                    to_parse.emplace_back(ParseContext::OR_D, -1, -1);
2081
24
                    script_size += 4;
2082
35
                } else if (Const("or_i(", in)) {
2083
35
                    to_parse.emplace_back(ParseContext::OR_I, -1, -1);
2084
35
                    script_size += 4;
2085
35
                } else {
2086
0
                    return {};
2087
0
                }
2088
6.30k
                to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
2089
6.30k
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2090
6.30k
                to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2091
6.30k
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2092
6.30k
            }
2093
12.9k
            break;
2094
12.9k
        }
2095
12.9k
        case ParseContext::ALT: {
2096
4.48k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A, Vector(std::move(constructed.back()))};
2097
4.48k
            break;
2098
12.9k
        }
2099
21
        case ParseContext::SWAP: {
2100
21
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S, Vector(std::move(constructed.back()))};
2101
21
            break;
2102
12.9k
        }
2103
54
        case ParseContext::CHECK: {
2104
54
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(std::move(constructed.back()))};
2105
54
            break;
2106
12.9k
        }
2107
8
        case ParseContext::DUP_IF: {
2108
8
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D, Vector(std::move(constructed.back()))};
2109
8
            break;
2110
12.9k
        }
2111
8
        case ParseContext::NON_ZERO: {
2112
8
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J, Vector(std::move(constructed.back()))};
2113
8
            break;
2114
12.9k
        }
2115
15
        case ParseContext::ZERO_NOTEQUAL: {
2116
15
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N, Vector(std::move(constructed.back()))};
2117
15
            break;
2118
12.9k
        }
2119
99
        case ParseContext::VERIFY: {
2120
99
            script_size += (constructed.back().GetType() << "x"_mst);
2121
99
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V, Vector(std::move(constructed.back()))};
2122
99
            break;
2123
12.9k
        }
2124
16
        case ParseContext::WRAP_U: {
2125
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})};
2126
16
            break;
2127
12.9k
        }
2128
43
        case ParseContext::WRAP_T: {
2129
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})};
2130
43
            break;
2131
12.9k
        }
2132
4.42k
        case ParseContext::AND_B: {
2133
4.42k
            BuildBack(ctx.MsContext(), Fragment::AND_B, constructed);
2134
4.42k
            break;
2135
12.9k
        }
2136
8
        case ParseContext::AND_N: {
2137
8
            auto mid = std::move(constructed.back());
2138
8
            constructed.pop_back();
2139
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})};
2140
8
            break;
2141
12.9k
        }
2142
38
        case ParseContext::AND_V: {
2143
38
            BuildBack(ctx.MsContext(), Fragment::AND_V, constructed);
2144
38
            break;
2145
12.9k
        }
2146
21
        case ParseContext::OR_B: {
2147
21
            BuildBack(ctx.MsContext(), Fragment::OR_B, constructed);
2148
21
            break;
2149
12.9k
        }
2150
14
        case ParseContext::OR_C: {
2151
14
            BuildBack(ctx.MsContext(), Fragment::OR_C, constructed);
2152
14
            break;
2153
12.9k
        }
2154
23
        case ParseContext::OR_D: {
2155
23
            BuildBack(ctx.MsContext(), Fragment::OR_D, constructed);
2156
23
            break;
2157
12.9k
        }
2158
73
        case ParseContext::OR_I: {
2159
73
            BuildBack(ctx.MsContext(), Fragment::OR_I, constructed);
2160
73
            break;
2161
12.9k
        }
2162
29
        case ParseContext::ANDOR: {
2163
29
            auto right = std::move(constructed.back());
2164
29
            constructed.pop_back();
2165
29
            auto mid = std::move(constructed.back());
2166
29
            constructed.pop_back();
2167
29
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR, Vector(std::move(constructed.back()), std::move(mid), std::move(right))};
2168
29
            break;
2169
12.9k
        }
2170
60
        case ParseContext::THRESH: {
2171
60
            if (in.size() < 1) return {};
2172
60
            if (in[0] == ',') {
2173
39
                in = in.subspan(1);
2174
39
                to_parse.emplace_back(ParseContext::THRESH, n+1, k);
2175
39
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2176
39
                script_size += 2;
2177
39
            } else if (in[0] == ')') {
2178
21
                if (k > n) return {};
2179
19
                in = in.subspan(1);
2180
                // Children are constructed in reverse order, so iterate from end to beginning
2181
19
                std::vector<Node<Key>> subs;
2182
75
                for (int i = 0; i < n; ++i) {
2183
56
                    subs.push_back(std::move(constructed.back()));
2184
56
                    constructed.pop_back();
2185
56
                }
2186
19
                std::reverse(subs.begin(), subs.end());
2187
19
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs), k);
2188
19
            } else {
2189
0
                return {};
2190
0
            }
2191
58
            break;
2192
60
        }
2193
6.34k
        case ParseContext::COMMA: {
2194
6.34k
            if (in.size() < 1 || in[0] != ',') return {};
2195
6.34k
            in = in.subspan(1);
2196
6.34k
            break;
2197
6.34k
        }
2198
4.59k
        case ParseContext::CLOSE_BRACKET: {
2199
4.59k
            if (in.size() < 1 || in[0] != ')') return {};
2200
4.59k
            in = in.subspan(1);
2201
4.59k
            break;
2202
4.59k
        }
2203
46.2k
        }
2204
46.2k
    }
2205
2206
    // Sanity checks on the produced miniscript
2207
220
    assert(constructed.size() >= 1);
2208
188
    CHECK_NONFATAL(constructed.size() == 1);
2209
188
    assert(constructed[0].ScriptSize() == script_size);
2210
188
    if (in.size() > 0) return {};
2211
188
    Node<Key> tl_node{std::move(constructed.front())};
2212
188
    tl_node.DuplicateKeyCheck(ctx);
2213
188
    return tl_node;
2214
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
1858
533
{
1859
533
    using namespace script;
1860
1861
    // Account for the minimum script size for all parsed fragments so far. It "borrows" 1
1862
    // script byte from all leaf nodes, counting it instead whenever a space for a recursive
1863
    // expression is added (through andor, and_*, or_*, thresh). This guarantees that all fragments
1864
    // increment the script_size by at least one, except for:
1865
    // - "0", "1": these leafs are only a single byte, so their subtracted-from increment is 0.
1866
    //   This is not an issue however, as "space" for them has to be created by combinators,
1867
    //   which do increment script_size.
1868
    // - "v:": the v wrapper adds nothing as in some cases it results in no opcode being added
1869
    //   (instead transforming another opcode into its VERIFY form). However, the v: wrapper has
1870
    //   to be interleaved with other fragments to be valid, so this is not a concern.
1871
533
    size_t script_size{1};
1872
533
    size_t max_size{internal::MaxScriptSize(ctx.MsContext())};
1873
1874
    // The two integers are used to hold state for thresh()
1875
533
    std::vector<std::tuple<ParseContext, int64_t, int64_t>> to_parse;
1876
533
    std::vector<Node<Key>> constructed;
1877
1878
533
    to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
1879
1880
    // Parses a multi() or multi_a() from its string representation. Returns false on parsing error.
1881
533
    const auto parse_multi_exp = [&](std::span<const char>& in, const bool is_multi_a) -> bool {
1882
533
        const auto max_keys{is_multi_a ? MAX_PUBKEYS_PER_MULTI_A : MAX_PUBKEYS_PER_MULTISIG};
1883
533
        const auto required_ctx{is_multi_a ? MiniscriptContext::TAPSCRIPT : MiniscriptContext::P2WSH};
1884
533
        if (ctx.MsContext() != required_ctx) return false;
1885
        // Get threshold
1886
533
        int next_comma = FindNextChar(in, ',');
1887
533
        if (next_comma < 1) return false;
1888
533
        const auto k_to_integral{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
1889
533
        if (!k_to_integral.has_value()) return false;
1890
533
        const int64_t k{k_to_integral.value()};
1891
533
        in = in.subspan(next_comma + 1);
1892
        // Get keys. It is compatible for both compressed and x-only keys.
1893
533
        std::vector<Key> keys;
1894
533
        while (next_comma != -1) {
1895
533
            next_comma = FindNextChar(in, ',');
1896
533
            int key_length = (next_comma == -1) ? FindNextChar(in, ')') : next_comma;
1897
533
            if (key_length < 1) return false;
1898
533
            std::span<const char> sp{in.begin(), in.begin() + key_length};
1899
533
            auto key = ctx.FromString(sp);
1900
533
            if (!key) return false;
1901
533
            keys.push_back(std::move(*key));
1902
533
            in = in.subspan(key_length + 1);
1903
533
        }
1904
533
        if (keys.size() < 1 || keys.size() > max_keys) return false;
1905
533
        if (k < 1 || k > (int64_t)keys.size()) return false;
1906
533
        if (is_multi_a) {
1907
            // (push + xonly-key + CHECKSIG[ADD]) * n + k + OP_NUMEQUAL(VERIFY), minus one.
1908
533
            script_size += (1 + 32 + 1) * keys.size() + BuildScript(k).size();
1909
533
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), k);
1910
533
        } else {
1911
533
            script_size += 2 + (keys.size() > 16) + (k > 16) + 34 * keys.size();
1912
533
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), k);
1913
533
        }
1914
533
        return true;
1915
533
    };
1916
1917
333k
    while (!to_parse.empty()) {
1918
333k
        if (script_size > max_size) return {};
1919
1920
        // Get the current context we are decoding within
1921
333k
        auto [cur_context, n, k] = to_parse.back();
1922
333k
        to_parse.pop_back();
1923
1924
333k
        switch (cur_context) {
1925
1.21k
        case ParseContext::WRAPPED_EXPR: {
1926
1.21k
            std::optional<size_t> colon_index{};
1927
662k
            for (size_t i = 1; i < in.size(); ++i) {
1928
662k
                if (in[i] == ':') {
1929
310
                    colon_index = i;
1930
310
                    break;
1931
310
                }
1932
662k
                if (in[i] < 'a' || in[i] > 'z') break;
1933
662k
            }
1934
            // If there is no colon, this loop won't execute
1935
1.21k
            bool last_was_v{false};
1936
660k
            for (size_t j = 0; colon_index && j < *colon_index; ++j) {
1937
659k
                if (script_size > max_size) return {};
1938
659k
                if (in[j] == 'a') {
1939
82
                    script_size += 2;
1940
82
                    to_parse.emplace_back(ParseContext::ALT, -1, -1);
1941
659k
                } else if (in[j] == 's') {
1942
51
                    script_size += 1;
1943
51
                    to_parse.emplace_back(ParseContext::SWAP, -1, -1);
1944
659k
                } else if (in[j] == 'c') {
1945
16
                    script_size += 1;
1946
16
                    to_parse.emplace_back(ParseContext::CHECK, -1, -1);
1947
659k
                } else if (in[j] == 'd') {
1948
10
                    script_size += 3;
1949
10
                    to_parse.emplace_back(ParseContext::DUP_IF, -1, -1);
1950
659k
                } else if (in[j] == 'j') {
1951
0
                    script_size += 4;
1952
0
                    to_parse.emplace_back(ParseContext::NON_ZERO, -1, -1);
1953
659k
                } else if (in[j] == 'n') {
1954
658k
                    script_size += 1;
1955
658k
                    to_parse.emplace_back(ParseContext::ZERO_NOTEQUAL, -1, -1);
1956
658k
                } else if (in[j] == 'v') {
1957
                    // do not permit "...vv...:"; it's not valid, and also doesn't trigger early
1958
                    // failure as script_size isn't incremented.
1959
158
                    if (last_was_v) return {};
1960
158
                    to_parse.emplace_back(ParseContext::VERIFY, -1, -1);
1961
158
                } else if (in[j] == 'u') {
1962
0
                    script_size += 4;
1963
0
                    to_parse.emplace_back(ParseContext::WRAP_U, -1, -1);
1964
18
                } else if (in[j] == 't') {
1965
2
                    script_size += 1;
1966
2
                    to_parse.emplace_back(ParseContext::WRAP_T, -1, -1);
1967
16
                } else if (in[j] == 'l') {
1968
                    // The l: wrapper is equivalent to or_i(0,X)
1969
16
                    script_size += 4;
1970
16
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
1971
16
                    to_parse.emplace_back(ParseContext::OR_I, -1, -1);
1972
16
                } else {
1973
0
                    return {};
1974
0
                }
1975
659k
                last_was_v = (in[j] == 'v');
1976
659k
            }
1977
1.21k
            to_parse.emplace_back(ParseContext::EXPR, -1, -1);
1978
1.21k
            if (colon_index) in = in.subspan(*colon_index + 1);
1979
1.21k
            break;
1980
1.21k
        }
1981
1.21k
        case ParseContext::EXPR: {
1982
1.21k
            if (Const("0", in)) {
1983
3
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
1984
1.21k
            } else if (Const("1", in)) {
1985
3
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1);
1986
1.21k
            } else if (Const("pk(", in, /*skip=*/false)) {
1987
251
                std::optional<Key> key = ParseKey<Key, Ctx>("pk", in, ctx);
1988
251
                if (!key) return {};
1989
249
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(Node<Key>(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_K, Vector(std::move(*key)))));
1990
249
                script_size += IsTapscript(ctx.MsContext()) ? 33 : 34;
1991
961
            } else if (Const("pkh(", in, /*skip=*/false)) {
1992
82
                std::optional<Key> key = ParseKey<Key, Ctx>("pkh", in, ctx);
1993
82
                if (!key) return {};
1994
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)))));
1995
82
                script_size += 24;
1996
879
            } else if (Const("pk_k(", in, /*skip=*/false)) {
1997
25
                std::optional<Key> key = ParseKey<Key, Ctx>("pk_k", in, ctx);
1998
25
                if (!key) return {};
1999
23
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_K, Vector(std::move(*key)));
2000
23
                script_size += IsTapscript(ctx.MsContext()) ? 32 : 33;
2001
854
            } else if (Const("pk_h(", in, /*skip=*/false)) {
2002
3
                std::optional<Key> key = ParseKey<Key, Ctx>("pk_h", in, ctx);
2003
3
                if (!key) return {};
2004
3
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_H, Vector(std::move(*key)));
2005
3
                script_size += 23;
2006
851
            } else if (Const("sha256(", in, /*skip=*/false)) {
2007
8
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("sha256", in, 32, ctx);
2008
8
                if (!hash) return {};
2009
8
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, std::move(*hash));
2010
8
                script_size += 38;
2011
843
            } else if (Const("ripemd160(", in, /*skip=*/false)) {
2012
8
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("ripemd160", in, 20, ctx);
2013
8
                if (!hash) return {};
2014
8
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::RIPEMD160, std::move(*hash));
2015
8
                script_size += 26;
2016
835
            } else if (Const("hash256(", in, /*skip=*/false)) {
2017
8
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("hash256", in, 32, ctx);
2018
8
                if (!hash) return {};
2019
8
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, std::move(*hash));
2020
8
                script_size += 38;
2021
827
            } else if (Const("hash160(", in, /*skip=*/false)) {
2022
16
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("hash160", in, 20, ctx);
2023
16
                if (!hash) return {};
2024
16
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, std::move(*hash));
2025
16
                script_size += 26;
2026
811
            } else if (Const("after(", in, /*skip=*/false)) {
2027
49
                auto expr = Expr(in);
2028
49
                if (!Func("after", expr)) return {};
2029
49
                const auto num{ToIntegral<int64_t>(std::string_view(expr.begin(), expr.end()))};
2030
49
                if (!num.has_value() || *num < 1 || *num >= 0x80000000L) return {};
2031
49
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num);
2032
49
                script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
2033
762
            } else if (Const("older(", in, /*skip=*/false)) {
2034
73
                auto expr = Expr(in);
2035
73
                if (!Func("older", expr)) return {};
2036
73
                const auto num{ToIntegral<int64_t>(std::string_view(expr.begin(), expr.end()))};
2037
73
                if (!num.has_value() || *num < 1 || *num >= 0x80000000L) return {};
2038
73
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num);
2039
73
                script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
2040
689
            } else if (Const("multi(", in)) {
2041
18
                if (!parse_multi_exp(in, /* is_multi_a = */false)) return {};
2042
671
            } else if (Const("multi_a(", in)) {
2043
14
                if (!parse_multi_exp(in, /* is_multi_a = */true)) return {};
2044
657
            } else if (Const("thresh(", in)) {
2045
33
                int next_comma = FindNextChar(in, ',');
2046
33
                if (next_comma < 1) return {};
2047
33
                const auto k{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
2048
33
                if (!k.has_value() || *k < 1) return {};
2049
33
                in = in.subspan(next_comma + 1);
2050
                // n = 1 here because we read the first WRAPPED_EXPR before reaching THRESH
2051
33
                to_parse.emplace_back(ParseContext::THRESH, 1, *k);
2052
33
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2053
33
                script_size += 2 + (*k > 16) + (*k > 0x7f) + (*k > 0x7fff) + (*k > 0x7fffff);
2054
624
            } else if (Const("andor(", in)) {
2055
25
                to_parse.emplace_back(ParseContext::ANDOR, -1, -1);
2056
25
                to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
2057
25
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2058
25
                to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2059
25
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2060
25
                to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2061
25
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2062
25
                script_size += 5;
2063
599
            } else {
2064
599
                if (Const("and_n(", in)) {
2065
8
                    to_parse.emplace_back(ParseContext::AND_N, -1, -1);
2066
8
                    script_size += 5;
2067
591
                } else if (Const("and_b(", in)) {
2068
41
                    to_parse.emplace_back(ParseContext::AND_B, -1, -1);
2069
41
                    script_size += 2;
2070
550
                } else if (Const("and_v(", in)) {
2071
142
                    to_parse.emplace_back(ParseContext::AND_V, -1, -1);
2072
142
                    script_size += 1;
2073
408
                } else if (Const("or_b(", in)) {
2074
23
                    to_parse.emplace_back(ParseContext::OR_B, -1, -1);
2075
23
                    script_size += 2;
2076
385
                } else if (Const("or_c(", in)) {
2077
12
                    to_parse.emplace_back(ParseContext::OR_C, -1, -1);
2078
12
                    script_size += 3;
2079
373
                } else if (Const("or_d(", in)) {
2080
18
                    to_parse.emplace_back(ParseContext::OR_D, -1, -1);
2081
18
                    script_size += 4;
2082
355
                } else if (Const("or_i(", in)) {
2083
10
                    to_parse.emplace_back(ParseContext::OR_I, -1, -1);
2084
10
                    script_size += 4;
2085
345
                } else {
2086
345
                    return {};
2087
345
                }
2088
254
                to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
2089
254
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2090
254
                to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2091
254
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2092
254
            }
2093
868
            break;
2094
1.21k
        }
2095
868
        case ParseContext::ALT: {
2096
82
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A, Vector(std::move(constructed.back()))};
2097
82
            break;
2098
1.21k
        }
2099
51
        case ParseContext::SWAP: {
2100
51
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S, Vector(std::move(constructed.back()))};
2101
51
            break;
2102
1.21k
        }
2103
14
        case ParseContext::CHECK: {
2104
14
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(std::move(constructed.back()))};
2105
14
            break;
2106
1.21k
        }
2107
10
        case ParseContext::DUP_IF: {
2108
10
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D, Vector(std::move(constructed.back()))};
2109
10
            break;
2110
1.21k
        }
2111
0
        case ParseContext::NON_ZERO: {
2112
0
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J, Vector(std::move(constructed.back()))};
2113
0
            break;
2114
1.21k
        }
2115
329k
        case ParseContext::ZERO_NOTEQUAL: {
2116
329k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N, Vector(std::move(constructed.back()))};
2117
329k
            break;
2118
1.21k
        }
2119
156
        case ParseContext::VERIFY: {
2120
156
            script_size += (constructed.back().GetType() << "x"_mst);
2121
156
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V, Vector(std::move(constructed.back()))};
2122
156
            break;
2123
1.21k
        }
2124
0
        case ParseContext::WRAP_U: {
2125
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})};
2126
0
            break;
2127
1.21k
        }
2128
2
        case ParseContext::WRAP_T: {
2129
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})};
2130
2
            break;
2131
1.21k
        }
2132
41
        case ParseContext::AND_B: {
2133
41
            BuildBack(ctx.MsContext(), Fragment::AND_B, constructed);
2134
41
            break;
2135
1.21k
        }
2136
8
        case ParseContext::AND_N: {
2137
8
            auto mid = std::move(constructed.back());
2138
8
            constructed.pop_back();
2139
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})};
2140
8
            break;
2141
1.21k
        }
2142
138
        case ParseContext::AND_V: {
2143
138
            BuildBack(ctx.MsContext(), Fragment::AND_V, constructed);
2144
138
            break;
2145
1.21k
        }
2146
23
        case ParseContext::OR_B: {
2147
23
            BuildBack(ctx.MsContext(), Fragment::OR_B, constructed);
2148
23
            break;
2149
1.21k
        }
2150
12
        case ParseContext::OR_C: {
2151
12
            BuildBack(ctx.MsContext(), Fragment::OR_C, constructed);
2152
12
            break;
2153
1.21k
        }
2154
18
        case ParseContext::OR_D: {
2155
18
            BuildBack(ctx.MsContext(), Fragment::OR_D, constructed);
2156
18
            break;
2157
1.21k
        }
2158
26
        case ParseContext::OR_I: {
2159
26
            BuildBack(ctx.MsContext(), Fragment::OR_I, constructed);
2160
26
            break;
2161
1.21k
        }
2162
23
        case ParseContext::ANDOR: {
2163
23
            auto right = std::move(constructed.back());
2164
23
            constructed.pop_back();
2165
23
            auto mid = std::move(constructed.back());
2166
23
            constructed.pop_back();
2167
23
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR, Vector(std::move(constructed.back()), std::move(mid), std::move(right))};
2168
23
            break;
2169
1.21k
        }
2170
104
        case ParseContext::THRESH: {
2171
104
            if (in.size() < 1) return {};
2172
104
            if (in[0] == ',') {
2173
71
                in = in.subspan(1);
2174
71
                to_parse.emplace_back(ParseContext::THRESH, n+1, k);
2175
71
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2176
71
                script_size += 2;
2177
71
            } else if (in[0] == ')') {
2178
33
                if (k > n) return {};
2179
33
                in = in.subspan(1);
2180
                // Children are constructed in reverse order, so iterate from end to beginning
2181
33
                std::vector<Node<Key>> subs;
2182
137
                for (int i = 0; i < n; ++i) {
2183
104
                    subs.push_back(std::move(constructed.back()));
2184
104
                    constructed.pop_back();
2185
104
                }
2186
33
                std::reverse(subs.begin(), subs.end());
2187
33
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs), k);
2188
33
            } else {
2189
0
                return {};
2190
0
            }
2191
104
            break;
2192
104
        }
2193
302
        case ParseContext::COMMA: {
2194
302
            if (in.size() < 1 || in[0] != ',') return {};
2195
302
            in = in.subspan(1);
2196
302
            break;
2197
302
        }
2198
273
        case ParseContext::CLOSE_BRACKET: {
2199
273
            if (in.size() < 1 || in[0] != ')') return {};
2200
273
            in = in.subspan(1);
2201
273
            break;
2202
273
        }
2203
333k
        }
2204
333k
    }
2205
2206
    // Sanity checks on the produced miniscript
2207
533
    assert(constructed.size() >= 1);
2208
182
    CHECK_NONFATAL(constructed.size() == 1);
2209
182
    assert(constructed[0].ScriptSize() == script_size);
2210
182
    if (in.size() > 0) return {};
2211
179
    Node<Key> tl_node{std::move(constructed.front())};
2212
179
    tl_node.DuplicateKeyCheck(ctx);
2213
179
    return tl_node;
2214
182
}
2215
2216
/** Decode a script into opcode/push pairs.
2217
 *
2218
 * Construct a vector with one element per opcode in the script, in reverse order.
2219
 * Each element is a pair consisting of the opcode, as well as the data pushed by
2220
 * the opcode (including OP_n), if any. OP_CHECKSIGVERIFY, OP_CHECKMULTISIGVERIFY,
2221
 * OP_NUMEQUALVERIFY and OP_EQUALVERIFY are decomposed into OP_CHECKSIG, OP_CHECKMULTISIG,
2222
 * OP_EQUAL and OP_NUMEQUAL respectively, plus OP_VERIFY.
2223
 */
2224
std::optional<std::vector<Opcode>> DecomposeScript(const CScript& script);
2225
2226
/** Determine whether the passed pair (created by DecomposeScript) is pushing a number. */
2227
std::optional<int64_t> ParseScriptNumber(const Opcode& in);
2228
2229
enum class DecodeContext {
2230
    /** A single expression of type B, K, or V. Specifically, this can't be an
2231
     * and_v or an expression of type W (a: and s: wrappers). */
2232
    SINGLE_BKV_EXPR,
2233
    /** Potentially multiple SINGLE_BKV_EXPRs as children of (potentially multiple)
2234
     * and_v expressions. Syntactic sugar for MAYBE_AND_V + SINGLE_BKV_EXPR. */
2235
    BKV_EXPR,
2236
    /** An expression of type W (a: or s: wrappers). */
2237
    W_EXPR,
2238
2239
    /** SWAP expects the next element to be OP_SWAP (inside a W-type expression that
2240
     * didn't end with FROMALTSTACK), and wraps the top of the constructed stack
2241
     * with s: */
2242
    SWAP,
2243
    /** ALT expects the next element to be TOALTSTACK (we must have already read a
2244
     * FROMALTSTACK earlier), and wraps the top of the constructed stack with a: */
2245
    ALT,
2246
    /** CHECK wraps the top constructed node with c: */
2247
    CHECK,
2248
    /** DUP_IF wraps the top constructed node with d: */
2249
    DUP_IF,
2250
    /** VERIFY wraps the top constructed node with v: */
2251
    VERIFY,
2252
    /** NON_ZERO wraps the top constructed node with j: */
2253
    NON_ZERO,
2254
    /** ZERO_NOTEQUAL wraps the top constructed node with n: */
2255
    ZERO_NOTEQUAL,
2256
2257
    /** MAYBE_AND_V will check if the next part of the script could be a valid
2258
     * miniscript sub-expression, and if so it will push AND_V and SINGLE_BKV_EXPR
2259
     * to decode it and construct the and_v node. This is recursive, to deal with
2260
     * multiple and_v nodes inside each other. */
2261
    MAYBE_AND_V,
2262
    /** AND_V will construct an and_v node from the last two constructed nodes. */
2263
    AND_V,
2264
    /** AND_B will construct an and_b node from the last two constructed nodes. */
2265
    AND_B,
2266
    /** ANDOR will construct an andor node from the last three constructed nodes. */
2267
    ANDOR,
2268
    /** OR_B will construct an or_b node from the last two constructed nodes. */
2269
    OR_B,
2270
    /** OR_C will construct an or_c node from the last two constructed nodes. */
2271
    OR_C,
2272
    /** OR_D will construct an or_d node from the last two constructed nodes. */
2273
    OR_D,
2274
2275
    /** In a thresh expression, all sub-expressions other than the first are W-type,
2276
     * and end in OP_ADD. THRESH_W will check for this OP_ADD and either push a W_EXPR
2277
     * or a SINGLE_BKV_EXPR and jump to THRESH_E accordingly. */
2278
    THRESH_W,
2279
    /** THRESH_E constructs a thresh node from the appropriate number of constructed
2280
     * children. */
2281
    THRESH_E,
2282
2283
    /** ENDIF signals that we are inside some sort of OP_IF structure, which could be
2284
     * or_d, or_c, or_i, andor, d:, or j: wrapper, depending on what follows. We read
2285
     * a BKV_EXPR and then deal with the next opcode case-by-case. */
2286
    ENDIF,
2287
    /** If, inside an ENDIF context, we find an OP_NOTIF before finding an OP_ELSE,
2288
     * we could either be in an or_d or an or_c node. We then check for IFDUP to
2289
     * distinguish these cases. */
2290
    ENDIF_NOTIF,
2291
    /** If, inside an ENDIF context, we find an OP_ELSE, then we could be in either an
2292
     * or_i or an andor node. Read the next BKV_EXPR and find either an OP_IF or an
2293
     * OP_NOTIF. */
2294
    ENDIF_ELSE,
2295
};
2296
2297
//! Parse a miniscript from a bitcoin script
2298
template <typename Key, typename Ctx, typename I>
2299
inline std::optional<Node<Key>> DecodeScript(I& in, I last, const Ctx& ctx)
2300
4.14k
{
2301
    // The two integers are used to hold state for thresh()
2302
4.14k
    std::vector<std::tuple<DecodeContext, int64_t, int64_t>> to_parse;
2303
4.14k
    std::vector<Node<Key>> constructed;
2304
2305
    // This is the top level, so we assume the type is B
2306
    // (in particular, disallowing top level W expressions)
2307
4.14k
    to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2308
2309
15.8M
    while (!to_parse.empty()) {
2310
        // Exit early if the Miniscript is not going to be valid.
2311
15.8M
        if (!constructed.empty() && !constructed.back().IsValid()) return {};
2312
2313
        // Get the current context we are decoding within
2314
15.8M
        auto [cur_context, n, k] = to_parse.back();
2315
15.8M
        to_parse.pop_back();
2316
2317
15.8M
        switch(cur_context) {
2318
7.92M
        case DecodeContext::SINGLE_BKV_EXPR: {
2319
7.92M
            if (in >= last) return {};
2320
2321
            // Constants
2322
7.92M
            if (in[0].first == OP_1) {
2323
80
                ++in;
2324
80
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1);
2325
80
                break;
2326
80
            }
2327
7.92M
            if (in[0].first == OP_0) {
2328
519
                ++in;
2329
519
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
2330
519
                break;
2331
519
            }
2332
            // Public keys
2333
7.92M
            if (in[0].second.size() == 33 || in[0].second.size() == 32) {
2334
4.21k
                auto key = ctx.FromPKBytes(in[0].second.begin(), in[0].second.end());
2335
4.21k
                if (!key) return {};
2336
4.20k
                ++in;
2337
4.20k
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_K, Vector(std::move(*key)));
2338
4.20k
                break;
2339
4.21k
            }
2340
7.92M
            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) {
2341
610
                auto key = ctx.FromPKHBytes(in[2].second.begin(), in[2].second.end());
2342
610
                if (!key) return {};
2343
607
                in += 5;
2344
607
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_H, Vector(std::move(*key)));
2345
607
                break;
2346
610
            }
2347
            // Time locks
2348
7.92M
            std::optional<int64_t> num;
2349
7.92M
            if (last - in >= 2 && in[0].first == OP_CHECKSEQUENCEVERIFY && (num = ParseScriptNumber(in[1]))) {
2350
2.37k
                in += 2;
2351
2.37k
                if (*num < 1 || *num > 0x7FFFFFFFL) return {};
2352
2.37k
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num);
2353
2.37k
                break;
2354
2.37k
            }
2355
7.91M
            if (last - in >= 2 && in[0].first == OP_CHECKLOCKTIMEVERIFY && (num = ParseScriptNumber(in[1]))) {
2356
975
                in += 2;
2357
975
                if (num < 1 || num > 0x7FFFFFFFL) return {};
2358
975
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num);
2359
975
                break;
2360
975
            }
2361
            // Hashes
2362
7.91M
            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) {
2363
274
                if (in[2].first == OP_SHA256 && in[1].second.size() == 32) {
2364
74
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, in[1].second);
2365
74
                    in += 7;
2366
74
                    break;
2367
200
                } else if (in[2].first == OP_RIPEMD160 && in[1].second.size() == 20) {
2368
55
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::RIPEMD160, in[1].second);
2369
55
                    in += 7;
2370
55
                    break;
2371
145
                } else if (in[2].first == OP_HASH256 && in[1].second.size() == 32) {
2372
86
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, in[1].second);
2373
86
                    in += 7;
2374
86
                    break;
2375
86
                } else if (in[2].first == OP_HASH160 && in[1].second.size() == 20) {
2376
59
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, in[1].second);
2377
59
                    in += 7;
2378
59
                    break;
2379
59
                }
2380
274
            }
2381
            // Multi
2382
7.91M
            if (last - in >= 3 && in[0].first == OP_CHECKMULTISIG) {
2383
126
                if (IsTapscript(ctx.MsContext())) return {};
2384
126
                std::vector<Key> keys;
2385
126
                const auto n = ParseScriptNumber(in[1]);
2386
126
                if (!n || last - in < 3 + *n) return {};
2387
126
                if (*n < 1 || *n > 20) return {};
2388
419
                for (int i = 0; i < *n; ++i) {
2389
293
                    if (in[2 + i].second.size() != 33) return {};
2390
293
                    auto key = ctx.FromPKBytes(in[2 + i].second.begin(), in[2 + i].second.end());
2391
293
                    if (!key) return {};
2392
293
                    keys.push_back(std::move(*key));
2393
293
                }
2394
126
                const auto k = ParseScriptNumber(in[2 + *n]);
2395
126
                if (!k || *k < 1 || *k > *n) return {};
2396
126
                in += 3 + *n;
2397
126
                std::reverse(keys.begin(), keys.end());
2398
126
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), *k);
2399
126
                break;
2400
126
            }
2401
            // Tapscript's equivalent of multi
2402
7.91M
            if (last - in >= 4 && in[0].first == OP_NUMEQUAL) {
2403
780
                if (!IsTapscript(ctx.MsContext())) return {};
2404
                // The necessary threshold of signatures.
2405
780
                const auto k = ParseScriptNumber(in[1]);
2406
780
                if (!k) return {};
2407
780
                if (*k < 1 || *k > MAX_PUBKEYS_PER_MULTI_A) return {};
2408
780
                if (last - in < 2 + *k * 2) return {};
2409
780
                std::vector<Key> keys;
2410
780
                keys.reserve(*k);
2411
                // Walk through the expected (pubkey, CHECKSIG[ADD]) pairs.
2412
90.5k
                for (int pos = 2;; pos += 2) {
2413
90.5k
                    if (last - in < pos + 2) return {};
2414
                    // Make sure it's indeed an x-only pubkey and a CHECKSIG[ADD], then parse the key.
2415
90.5k
                    if (in[pos].first != OP_CHECKSIGADD && in[pos].first != OP_CHECKSIG) return {};
2416
90.5k
                    if (in[pos + 1].second.size() != 32) return {};
2417
90.5k
                    auto key = ctx.FromPKBytes(in[pos + 1].second.begin(), in[pos + 1].second.end());
2418
90.5k
                    if (!key) return {};
2419
90.5k
                    keys.push_back(std::move(*key));
2420
                    // Make sure early we don't parse an arbitrary large expression.
2421
90.5k
                    if (keys.size() > MAX_PUBKEYS_PER_MULTI_A) return {};
2422
                    // OP_CHECKSIG means it was the last one to parse.
2423
90.5k
                    if (in[pos].first == OP_CHECKSIG) break;
2424
90.5k
                }
2425
779
                if (keys.size() < (size_t)*k) return {};
2426
779
                in += 2 + keys.size() * 2;
2427
779
                std::reverse(keys.begin(), keys.end());
2428
779
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), *k);
2429
779
                break;
2430
779
            }
2431
            /** In the following wrappers, we only need to push SINGLE_BKV_EXPR rather
2432
             * than BKV_EXPR, because and_v commutes with these wrappers. For example,
2433
             * c:and_v(X,Y) produces the same script as and_v(X,c:Y). */
2434
            // c: wrapper
2435
7.91M
            if (in[0].first == OP_CHECKSIG) {
2436
4.78k
                ++in;
2437
4.78k
                to_parse.emplace_back(DecodeContext::CHECK, -1, -1);
2438
4.78k
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2439
4.78k
                break;
2440
4.78k
            }
2441
            // v: wrapper
2442
7.91M
            if (in[0].first == OP_VERIFY) {
2443
1.30k
                ++in;
2444
1.30k
                to_parse.emplace_back(DecodeContext::VERIFY, -1, -1);
2445
1.30k
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2446
1.30k
                break;
2447
1.30k
            }
2448
            // n: wrapper
2449
7.91M
            if (in[0].first == OP_0NOTEQUAL) {
2450
7.90M
                ++in;
2451
7.90M
                to_parse.emplace_back(DecodeContext::ZERO_NOTEQUAL, -1, -1);
2452
7.90M
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2453
7.90M
                break;
2454
7.90M
            }
2455
            // Thresh
2456
3.89k
            if (last - in >= 3 && in[0].first == OP_EQUAL && (num = ParseScriptNumber(in[1]))) {
2457
323
                if (*num < 1) return {};
2458
323
                in += 2;
2459
323
                to_parse.emplace_back(DecodeContext::THRESH_W, 0, *num);
2460
323
                break;
2461
323
            }
2462
            // OP_ENDIF can be WRAP_J, WRAP_D, ANDOR, OR_C, OR_D, or OR_I
2463
3.57k
            if (in[0].first == OP_ENDIF) {
2464
847
                ++in;
2465
847
                to_parse.emplace_back(DecodeContext::ENDIF, -1, -1);
2466
847
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2467
847
                break;
2468
847
            }
2469
            /** In and_b and or_b nodes, we only look for SINGLE_BKV_EXPR, because
2470
             * or_b(and_v(X,Y),Z) has script [X] [Y] [Z] OP_BOOLOR, the same as
2471
             * and_v(X,or_b(Y,Z)). In this example, the former of these is invalid as
2472
             * miniscript, while the latter is valid. So we leave the and_v "outside"
2473
             * while decoding. */
2474
            // and_b
2475
2.72k
            if (in[0].first == OP_BOOLAND) {
2476
2.69k
                ++in;
2477
2.69k
                to_parse.emplace_back(DecodeContext::AND_B, -1, -1);
2478
2.69k
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2479
2.69k
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2480
2.69k
                break;
2481
2.69k
            }
2482
            // or_b
2483
38
            if (in[0].first == OP_BOOLOR) {
2484
28
                ++in;
2485
28
                to_parse.emplace_back(DecodeContext::OR_B, -1, -1);
2486
28
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2487
28
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2488
28
                break;
2489
28
            }
2490
            // Unrecognised expression
2491
10
            return {};
2492
38
        }
2493
10.5k
        case DecodeContext::BKV_EXPR: {
2494
10.5k
            to_parse.emplace_back(DecodeContext::MAYBE_AND_V, -1, -1);
2495
10.5k
            to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2496
10.5k
            break;
2497
38
        }
2498
3.69k
        case DecodeContext::W_EXPR: {
2499
            // a: wrapper
2500
3.69k
            if (in >= last) return {};
2501
3.69k
            if (in[0].first == OP_FROMALTSTACK) {
2502
2.93k
                ++in;
2503
2.93k
                to_parse.emplace_back(DecodeContext::ALT, -1, -1);
2504
2.93k
            } else {
2505
758
                to_parse.emplace_back(DecodeContext::SWAP, -1, -1);
2506
758
            }
2507
3.69k
            to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2508
3.69k
            break;
2509
3.69k
        }
2510
10.5k
        case DecodeContext::MAYBE_AND_V: {
2511
            // If we reach a potential AND_V top-level, check if the next part of the script could be another AND_V child
2512
            // These op-codes cannot end any well-formed miniscript so cannot be used in an and_v node.
2513
10.5k
            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) {
2514
1.20k
                to_parse.emplace_back(DecodeContext::AND_V, -1, -1);
2515
                // BKV_EXPR can contain more AND_V nodes
2516
1.20k
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2517
1.20k
            }
2518
10.5k
            break;
2519
3.69k
        }
2520
758
        case DecodeContext::SWAP: {
2521
758
            if (in >= last || in[0].first != OP_SWAP || constructed.empty()) return {};
2522
758
            ++in;
2523
758
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S, Vector(std::move(constructed.back()))};
2524
758
            break;
2525
758
        }
2526
2.93k
        case DecodeContext::ALT: {
2527
2.93k
            if (in >= last || in[0].first != OP_TOALTSTACK || constructed.empty()) return {};
2528
2.93k
            ++in;
2529
2.93k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A, Vector(std::move(constructed.back()))};
2530
2.93k
            break;
2531
2.93k
        }
2532
4.78k
        case DecodeContext::CHECK: {
2533
4.78k
            if (constructed.empty()) return {};
2534
4.78k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(std::move(constructed.back()))};
2535
4.78k
            break;
2536
4.78k
        }
2537
94
        case DecodeContext::DUP_IF: {
2538
94
            if (constructed.empty()) return {};
2539
94
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D, Vector(std::move(constructed.back()))};
2540
94
            break;
2541
94
        }
2542
1.30k
        case DecodeContext::VERIFY: {
2543
1.30k
            if (constructed.empty()) return {};
2544
1.30k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V, Vector(std::move(constructed.back()))};
2545
1.30k
            break;
2546
1.30k
        }
2547
8
        case DecodeContext::NON_ZERO: {
2548
8
            if (constructed.empty()) return {};
2549
8
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J, Vector(std::move(constructed.back()))};
2550
8
            break;
2551
8
        }
2552
7.90M
        case DecodeContext::ZERO_NOTEQUAL: {
2553
7.90M
            if (constructed.empty()) return {};
2554
7.90M
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N, Vector(std::move(constructed.back()))};
2555
7.90M
            break;
2556
7.90M
        }
2557
1.20k
        case DecodeContext::AND_V: {
2558
1.20k
            if (constructed.size() < 2) return {};
2559
1.20k
            BuildBack(ctx.MsContext(), Fragment::AND_V, constructed, /*reverse=*/true);
2560
1.20k
            break;
2561
1.20k
        }
2562
2.69k
        case DecodeContext::AND_B: {
2563
2.69k
            if (constructed.size() < 2) return {};
2564
2.69k
            BuildBack(ctx.MsContext(), Fragment::AND_B, constructed, /*reverse=*/true);
2565
2.69k
            break;
2566
2.69k
        }
2567
28
        case DecodeContext::OR_B: {
2568
28
            if (constructed.size() < 2) return {};
2569
28
            BuildBack(ctx.MsContext(), Fragment::OR_B, constructed, /*reverse=*/true);
2570
28
            break;
2571
28
        }
2572
22
        case DecodeContext::OR_C: {
2573
22
            if (constructed.size() < 2) return {};
2574
22
            BuildBack(ctx.MsContext(), Fragment::OR_C, constructed, /*reverse=*/true);
2575
22
            break;
2576
22
        }
2577
62
        case DecodeContext::OR_D: {
2578
62
            if (constructed.size() < 2) return {};
2579
62
            BuildBack(ctx.MsContext(), Fragment::OR_D, constructed, /*reverse=*/true);
2580
62
            break;
2581
62
        }
2582
170
        case DecodeContext::ANDOR: {
2583
170
            if (constructed.size() < 3) return {};
2584
170
            Node left{std::move(constructed.back())};
2585
170
            constructed.pop_back();
2586
170
            Node right{std::move(constructed.back())};
2587
170
            constructed.pop_back();
2588
170
            Node mid{std::move(constructed.back())};
2589
170
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR, Vector(std::move(left), std::move(mid), std::move(right))};
2590
170
            break;
2591
170
        }
2592
1.29k
        case DecodeContext::THRESH_W: {
2593
1.29k
            if (in >= last) return {};
2594
1.29k
            if (in[0].first == OP_ADD) {
2595
976
                ++in;
2596
976
                to_parse.emplace_back(DecodeContext::THRESH_W, n+1, k);
2597
976
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2598
976
            } else {
2599
323
                to_parse.emplace_back(DecodeContext::THRESH_E, n+1, k);
2600
                // All children of thresh have type modifier d, so cannot be and_v
2601
323
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2602
323
            }
2603
1.29k
            break;
2604
1.29k
        }
2605
323
        case DecodeContext::THRESH_E: {
2606
323
            if (k < 1 || k > n || constructed.size() < static_cast<size_t>(n)) return {};
2607
323
            std::vector<Node<Key>> subs;
2608
1.62k
            for (int i = 0; i < n; ++i) {
2609
1.29k
                Node sub{std::move(constructed.back())};
2610
1.29k
                constructed.pop_back();
2611
1.29k
                subs.push_back(std::move(sub));
2612
1.29k
            }
2613
323
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs), k);
2614
323
            break;
2615
323
        }
2616
846
        case DecodeContext::ENDIF: {
2617
846
            if (in >= last) return {};
2618
2619
            // could be andor or or_i
2620
846
            if (in[0].first == OP_ELSE) {
2621
660
                ++in;
2622
660
                to_parse.emplace_back(DecodeContext::ENDIF_ELSE, -1, -1);
2623
660
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2624
660
            }
2625
            // could be j: or d: wrapper
2626
186
            else if (in[0].first == OP_IF) {
2627
102
                if (last - in >= 2 && in[1].first == OP_DUP) {
2628
94
                    in += 2;
2629
94
                    to_parse.emplace_back(DecodeContext::DUP_IF, -1, -1);
2630
94
                } else if (last - in >= 3 && in[1].first == OP_0NOTEQUAL && in[2].first == OP_SIZE) {
2631
8
                    in += 3;
2632
8
                    to_parse.emplace_back(DecodeContext::NON_ZERO, -1, -1);
2633
8
                }
2634
0
                else {
2635
0
                    return {};
2636
0
                }
2637
            // could be or_c or or_d
2638
102
            } else if (in[0].first == OP_NOTIF) {
2639
84
                ++in;
2640
84
                to_parse.emplace_back(DecodeContext::ENDIF_NOTIF, -1, -1);
2641
84
            }
2642
0
            else {
2643
0
                return {};
2644
0
            }
2645
846
            break;
2646
846
        }
2647
846
        case DecodeContext::ENDIF_NOTIF: {
2648
84
            if (in >= last) return {};
2649
84
            if (in[0].first == OP_IFDUP) {
2650
62
                ++in;
2651
62
                to_parse.emplace_back(DecodeContext::OR_D, -1, -1);
2652
62
            } else {
2653
22
                to_parse.emplace_back(DecodeContext::OR_C, -1, -1);
2654
22
            }
2655
            // or_c and or_d both require X to have type modifier d so, can't contain and_v
2656
84
            to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2657
84
            break;
2658
84
        }
2659
660
        case DecodeContext::ENDIF_ELSE: {
2660
660
            if (in >= last) return {};
2661
660
            if (in[0].first == OP_IF) {
2662
490
                ++in;
2663
490
                BuildBack(ctx.MsContext(), Fragment::OR_I, constructed, /*reverse=*/true);
2664
490
            } else if (in[0].first == OP_NOTIF) {
2665
170
                ++in;
2666
170
                to_parse.emplace_back(DecodeContext::ANDOR, -1, -1);
2667
                // andor requires X to have type modifier d, so it can't be and_v
2668
170
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2669
170
            } else {
2670
0
                return {};
2671
0
            }
2672
660
            break;
2673
660
        }
2674
15.8M
        }
2675
15.8M
    }
2676
4.12k
    if (constructed.size() != 1) return {};
2677
4.12k
    Node tl_node{std::move(constructed.front())};
2678
4.12k
    tl_node.DuplicateKeyCheck(ctx);
2679
    // Note that due to how ComputeType works (only assign the type to the node if the
2680
    // subs' types are valid) this would fail if any node of tree is badly typed.
2681
4.12k
    if (!tl_node.IsValidTopLevel()) return {};
2682
4.12k
    return tl_node;
2683
4.12k
}
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
2300
128
{
2301
    // The two integers are used to hold state for thresh()
2302
128
    std::vector<std::tuple<DecodeContext, int64_t, int64_t>> to_parse;
2303
128
    std::vector<Node<Key>> constructed;
2304
2305
    // This is the top level, so we assume the type is B
2306
    // (in particular, disallowing top level W expressions)
2307
128
    to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2308
2309
20.2k
    while (!to_parse.empty()) {
2310
        // Exit early if the Miniscript is not going to be valid.
2311
20.1k
        if (!constructed.empty() && !constructed.back().IsValid()) return {};
2312
2313
        // Get the current context we are decoding within
2314
20.1k
        auto [cur_context, n, k] = to_parse.back();
2315
20.1k
        to_parse.pop_back();
2316
2317
20.1k
        switch(cur_context) {
2318
5.95k
        case DecodeContext::SINGLE_BKV_EXPR: {
2319
5.95k
            if (in >= last) return {};
2320
2321
            // Constants
2322
5.95k
            if (in[0].first == OP_1) {
2323
77
                ++in;
2324
77
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1);
2325
77
                break;
2326
77
            }
2327
5.87k
            if (in[0].first == OP_0) {
2328
83
                ++in;
2329
83
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
2330
83
                break;
2331
83
            }
2332
            // Public keys
2333
5.79k
            if (in[0].second.size() == 33 || in[0].second.size() == 32) {
2334
454
                auto key = ctx.FromPKBytes(in[0].second.begin(), in[0].second.end());
2335
454
                if (!key) return {};
2336
454
                ++in;
2337
454
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_K, Vector(std::move(*key)));
2338
454
                break;
2339
454
            }
2340
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) {
2341
26
                auto key = ctx.FromPKHBytes(in[2].second.begin(), in[2].second.end());
2342
26
                if (!key) return {};
2343
26
                in += 5;
2344
26
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_H, Vector(std::move(*key)));
2345
26
                break;
2346
26
            }
2347
            // Time locks
2348
5.31k
            std::optional<int64_t> num;
2349
5.31k
            if (last - in >= 2 && in[0].first == OP_CHECKSEQUENCEVERIFY && (num = ParseScriptNumber(in[1]))) {
2350
2.03k
                in += 2;
2351
2.03k
                if (*num < 1 || *num > 0x7FFFFFFFL) return {};
2352
2.03k
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num);
2353
2.03k
                break;
2354
2.03k
            }
2355
3.27k
            if (last - in >= 2 && in[0].first == OP_CHECKLOCKTIMEVERIFY && (num = ParseScriptNumber(in[1]))) {
2356
65
                in += 2;
2357
65
                if (num < 1 || num > 0x7FFFFFFFL) return {};
2358
65
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num);
2359
65
                break;
2360
65
            }
2361
            // Hashes
2362
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) {
2363
48
                if (in[2].first == OP_SHA256 && in[1].second.size() == 32) {
2364
21
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, in[1].second);
2365
21
                    in += 7;
2366
21
                    break;
2367
27
                } else if (in[2].first == OP_RIPEMD160 && in[1].second.size() == 20) {
2368
7
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::RIPEMD160, in[1].second);
2369
7
                    in += 7;
2370
7
                    break;
2371
20
                } else if (in[2].first == OP_HASH256 && in[1].second.size() == 32) {
2372
14
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, in[1].second);
2373
14
                    in += 7;
2374
14
                    break;
2375
14
                } else if (in[2].first == OP_HASH160 && in[1].second.size() == 20) {
2376
6
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, in[1].second);
2377
6
                    in += 7;
2378
6
                    break;
2379
6
                }
2380
48
            }
2381
            // Multi
2382
3.16k
            if (last - in >= 3 && in[0].first == OP_CHECKMULTISIG) {
2383
12
                if (IsTapscript(ctx.MsContext())) return {};
2384
12
                std::vector<Key> keys;
2385
12
                const auto n = ParseScriptNumber(in[1]);
2386
12
                if (!n || last - in < 3 + *n) return {};
2387
12
                if (*n < 1 || *n > 20) return {};
2388
35
                for (int i = 0; i < *n; ++i) {
2389
23
                    if (in[2 + i].second.size() != 33) return {};
2390
23
                    auto key = ctx.FromPKBytes(in[2 + i].second.begin(), in[2 + i].second.end());
2391
23
                    if (!key) return {};
2392
23
                    keys.push_back(std::move(*key));
2393
23
                }
2394
12
                const auto k = ParseScriptNumber(in[2 + *n]);
2395
12
                if (!k || *k < 1 || *k > *n) return {};
2396
12
                in += 3 + *n;
2397
12
                std::reverse(keys.begin(), keys.end());
2398
12
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), *k);
2399
12
                break;
2400
12
            }
2401
            // Tapscript's equivalent of multi
2402
3.15k
            if (last - in >= 4 && in[0].first == OP_NUMEQUAL) {
2403
4
                if (!IsTapscript(ctx.MsContext())) return {};
2404
                // The necessary threshold of signatures.
2405
4
                const auto k = ParseScriptNumber(in[1]);
2406
4
                if (!k) return {};
2407
4
                if (*k < 1 || *k > MAX_PUBKEYS_PER_MULTI_A) return {};
2408
4
                if (last - in < 2 + *k * 2) return {};
2409
4
                std::vector<Key> keys;
2410
4
                keys.reserve(*k);
2411
                // Walk through the expected (pubkey, CHECKSIG[ADD]) pairs.
2412
27
                for (int pos = 2;; pos += 2) {
2413
27
                    if (last - in < pos + 2) return {};
2414
                    // Make sure it's indeed an x-only pubkey and a CHECKSIG[ADD], then parse the key.
2415
26
                    if (in[pos].first != OP_CHECKSIGADD && in[pos].first != OP_CHECKSIG) return {};
2416
26
                    if (in[pos + 1].second.size() != 32) return {};
2417
26
                    auto key = ctx.FromPKBytes(in[pos + 1].second.begin(), in[pos + 1].second.end());
2418
26
                    if (!key) return {};
2419
26
                    keys.push_back(std::move(*key));
2420
                    // Make sure early we don't parse an arbitrary large expression.
2421
26
                    if (keys.size() > MAX_PUBKEYS_PER_MULTI_A) return {};
2422
                    // OP_CHECKSIG means it was the last one to parse.
2423
26
                    if (in[pos].first == OP_CHECKSIG) break;
2424
26
                }
2425
3
                if (keys.size() < (size_t)*k) return {};
2426
3
                in += 2 + keys.size() * 2;
2427
3
                std::reverse(keys.begin(), keys.end());
2428
3
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), *k);
2429
3
                break;
2430
3
            }
2431
            /** In the following wrappers, we only need to push SINGLE_BKV_EXPR rather
2432
             * than BKV_EXPR, because and_v commutes with these wrappers. For example,
2433
             * c:and_v(X,Y) produces the same script as and_v(X,c:Y). */
2434
            // c: wrapper
2435
3.14k
            if (in[0].first == OP_CHECKSIG) {
2436
465
                ++in;
2437
465
                to_parse.emplace_back(DecodeContext::CHECK, -1, -1);
2438
465
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2439
465
                break;
2440
465
            }
2441
            // v: wrapper
2442
2.68k
            if (in[0].first == OP_VERIFY) {
2443
81
                ++in;
2444
81
                to_parse.emplace_back(DecodeContext::VERIFY, -1, -1);
2445
81
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2446
81
                break;
2447
81
            }
2448
            // n: wrapper
2449
2.60k
            if (in[0].first == OP_0NOTEQUAL) {
2450
15
                ++in;
2451
15
                to_parse.emplace_back(DecodeContext::ZERO_NOTEQUAL, -1, -1);
2452
15
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2453
15
                break;
2454
15
            }
2455
            // Thresh
2456
2.58k
            if (last - in >= 3 && in[0].first == OP_EQUAL && (num = ParseScriptNumber(in[1]))) {
2457
16
                if (*num < 1) return {};
2458
16
                in += 2;
2459
16
                to_parse.emplace_back(DecodeContext::THRESH_W, 0, *num);
2460
16
                break;
2461
16
            }
2462
            // OP_ENDIF can be WRAP_J, WRAP_D, ANDOR, OR_C, OR_D, or OR_I
2463
2.56k
            if (in[0].first == OP_ENDIF) {
2464
142
                ++in;
2465
142
                to_parse.emplace_back(DecodeContext::ENDIF, -1, -1);
2466
142
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2467
142
                break;
2468
142
            }
2469
            /** In and_b and or_b nodes, we only look for SINGLE_BKV_EXPR, because
2470
             * or_b(and_v(X,Y),Z) has script [X] [Y] [Z] OP_BOOLOR, the same as
2471
             * and_v(X,or_b(Y,Z)). In this example, the former of these is invalid as
2472
             * miniscript, while the latter is valid. So we leave the and_v "outside"
2473
             * while decoding. */
2474
            // and_b
2475
2.42k
            if (in[0].first == OP_BOOLAND) {
2476
2.41k
                ++in;
2477
2.41k
                to_parse.emplace_back(DecodeContext::AND_B, -1, -1);
2478
2.41k
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2479
2.41k
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2480
2.41k
                break;
2481
2.41k
            }
2482
            // or_b
2483
9
            if (in[0].first == OP_BOOLOR) {
2484
8
                ++in;
2485
8
                to_parse.emplace_back(DecodeContext::OR_B, -1, -1);
2486
8
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2487
8
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2488
8
                break;
2489
8
            }
2490
            // Unrecognised expression
2491
1
            return {};
2492
9
        }
2493
2.90k
        case DecodeContext::BKV_EXPR: {
2494
2.90k
            to_parse.emplace_back(DecodeContext::MAYBE_AND_V, -1, -1);
2495
2.90k
            to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2496
2.90k
            break;
2497
9
        }
2498
2.45k
        case DecodeContext::W_EXPR: {
2499
            // a: wrapper
2500
2.45k
            if (in >= last) return {};
2501
2.45k
            if (in[0].first == OP_FROMALTSTACK) {
2502
2.44k
                ++in;
2503
2.44k
                to_parse.emplace_back(DecodeContext::ALT, -1, -1);
2504
2.44k
            } else {
2505
10
                to_parse.emplace_back(DecodeContext::SWAP, -1, -1);
2506
10
            }
2507
2.45k
            to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2508
2.45k
            break;
2509
2.45k
        }
2510
2.89k
        case DecodeContext::MAYBE_AND_V: {
2511
            // If we reach a potential AND_V top-level, check if the next part of the script could be another AND_V child
2512
            // These op-codes cannot end any well-formed miniscript so cannot be used in an and_v node.
2513
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) {
2514
67
                to_parse.emplace_back(DecodeContext::AND_V, -1, -1);
2515
                // BKV_EXPR can contain more AND_V nodes
2516
67
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2517
67
            }
2518
2.89k
            break;
2519
2.45k
        }
2520
10
        case DecodeContext::SWAP: {
2521
10
            if (in >= last || in[0].first != OP_SWAP || constructed.empty()) return {};
2522
10
            ++in;
2523
10
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S, Vector(std::move(constructed.back()))};
2524
10
            break;
2525
10
        }
2526
2.44k
        case DecodeContext::ALT: {
2527
2.44k
            if (in >= last || in[0].first != OP_TOALTSTACK || constructed.empty()) return {};
2528
2.44k
            ++in;
2529
2.44k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A, Vector(std::move(constructed.back()))};
2530
2.44k
            break;
2531
2.44k
        }
2532
464
        case DecodeContext::CHECK: {
2533
464
            if (constructed.empty()) return {};
2534
464
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(std::move(constructed.back()))};
2535
464
            break;
2536
464
        }
2537
5
        case DecodeContext::DUP_IF: {
2538
5
            if (constructed.empty()) return {};
2539
5
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D, Vector(std::move(constructed.back()))};
2540
5
            break;
2541
5
        }
2542
81
        case DecodeContext::VERIFY: {
2543
81
            if (constructed.empty()) return {};
2544
81
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V, Vector(std::move(constructed.back()))};
2545
81
            break;
2546
81
        }
2547
8
        case DecodeContext::NON_ZERO: {
2548
8
            if (constructed.empty()) return {};
2549
8
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J, Vector(std::move(constructed.back()))};
2550
8
            break;
2551
8
        }
2552
15
        case DecodeContext::ZERO_NOTEQUAL: {
2553
15
            if (constructed.empty()) return {};
2554
15
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N, Vector(std::move(constructed.back()))};
2555
15
            break;
2556
15
        }
2557
66
        case DecodeContext::AND_V: {
2558
66
            if (constructed.size() < 2) return {};
2559
66
            BuildBack(ctx.MsContext(), Fragment::AND_V, constructed, /*reverse=*/true);
2560
66
            break;
2561
66
        }
2562
2.41k
        case DecodeContext::AND_B: {
2563
2.41k
            if (constructed.size() < 2) return {};
2564
2.41k
            BuildBack(ctx.MsContext(), Fragment::AND_B, constructed, /*reverse=*/true);
2565
2.41k
            break;
2566
2.41k
        }
2567
8
        case DecodeContext::OR_B: {
2568
8
            if (constructed.size() < 2) return {};
2569
8
            BuildBack(ctx.MsContext(), Fragment::OR_B, constructed, /*reverse=*/true);
2570
8
            break;
2571
8
        }
2572
6
        case DecodeContext::OR_C: {
2573
6
            if (constructed.size() < 2) return {};
2574
6
            BuildBack(ctx.MsContext(), Fragment::OR_C, constructed, /*reverse=*/true);
2575
6
            break;
2576
6
        }
2577
15
        case DecodeContext::OR_D: {
2578
15
            if (constructed.size() < 2) return {};
2579
15
            BuildBack(ctx.MsContext(), Fragment::OR_D, constructed, /*reverse=*/true);
2580
15
            break;
2581
15
        }
2582
29
        case DecodeContext::ANDOR: {
2583
29
            if (constructed.size() < 3) return {};
2584
29
            Node left{std::move(constructed.back())};
2585
29
            constructed.pop_back();
2586
29
            Node right{std::move(constructed.back())};
2587
29
            constructed.pop_back();
2588
29
            Node mid{std::move(constructed.back())};
2589
29
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR, Vector(std::move(left), std::move(mid), std::move(right))};
2590
29
            break;
2591
29
        }
2592
46
        case DecodeContext::THRESH_W: {
2593
46
            if (in >= last) return {};
2594
46
            if (in[0].first == OP_ADD) {
2595
30
                ++in;
2596
30
                to_parse.emplace_back(DecodeContext::THRESH_W, n+1, k);
2597
30
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2598
30
            } else {
2599
16
                to_parse.emplace_back(DecodeContext::THRESH_E, n+1, k);
2600
                // All children of thresh have type modifier d, so cannot be and_v
2601
16
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2602
16
            }
2603
46
            break;
2604
46
        }
2605
16
        case DecodeContext::THRESH_E: {
2606
16
            if (k < 1 || k > n || constructed.size() < static_cast<size_t>(n)) return {};
2607
16
            std::vector<Node<Key>> subs;
2608
62
            for (int i = 0; i < n; ++i) {
2609
46
                Node sub{std::move(constructed.back())};
2610
46
                constructed.pop_back();
2611
46
                subs.push_back(std::move(sub));
2612
46
            }
2613
16
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs), k);
2614
16
            break;
2615
16
        }
2616
142
        case DecodeContext::ENDIF: {
2617
142
            if (in >= last) return {};
2618
2619
            // could be andor or or_i
2620
142
            if (in[0].first == OP_ELSE) {
2621
108
                ++in;
2622
108
                to_parse.emplace_back(DecodeContext::ENDIF_ELSE, -1, -1);
2623
108
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2624
108
            }
2625
            // could be j: or d: wrapper
2626
34
            else if (in[0].first == OP_IF) {
2627
13
                if (last - in >= 2 && in[1].first == OP_DUP) {
2628
5
                    in += 2;
2629
5
                    to_parse.emplace_back(DecodeContext::DUP_IF, -1, -1);
2630
8
                } else if (last - in >= 3 && in[1].first == OP_0NOTEQUAL && in[2].first == OP_SIZE) {
2631
8
                    in += 3;
2632
8
                    to_parse.emplace_back(DecodeContext::NON_ZERO, -1, -1);
2633
8
                }
2634
0
                else {
2635
0
                    return {};
2636
0
                }
2637
            // could be or_c or or_d
2638
21
            } else if (in[0].first == OP_NOTIF) {
2639
21
                ++in;
2640
21
                to_parse.emplace_back(DecodeContext::ENDIF_NOTIF, -1, -1);
2641
21
            }
2642
0
            else {
2643
0
                return {};
2644
0
            }
2645
142
            break;
2646
142
        }
2647
142
        case DecodeContext::ENDIF_NOTIF: {
2648
21
            if (in >= last) return {};
2649
21
            if (in[0].first == OP_IFDUP) {
2650
15
                ++in;
2651
15
                to_parse.emplace_back(DecodeContext::OR_D, -1, -1);
2652
15
            } else {
2653
6
                to_parse.emplace_back(DecodeContext::OR_C, -1, -1);
2654
6
            }
2655
            // or_c and or_d both require X to have type modifier d so, can't contain and_v
2656
21
            to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2657
21
            break;
2658
21
        }
2659
108
        case DecodeContext::ENDIF_ELSE: {
2660
108
            if (in >= last) return {};
2661
108
            if (in[0].first == OP_IF) {
2662
79
                ++in;
2663
79
                BuildBack(ctx.MsContext(), Fragment::OR_I, constructed, /*reverse=*/true);
2664
79
            } else if (in[0].first == OP_NOTIF) {
2665
29
                ++in;
2666
29
                to_parse.emplace_back(DecodeContext::ANDOR, -1, -1);
2667
                // andor requires X to have type modifier d, so it can't be and_v
2668
29
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2669
29
            } else {
2670
0
                return {};
2671
0
            }
2672
108
            break;
2673
108
        }
2674
20.1k
        }
2675
20.1k
    }
2676
125
    if (constructed.size() != 1) return {};
2677
125
    Node tl_node{std::move(constructed.front())};
2678
125
    tl_node.DuplicateKeyCheck(ctx);
2679
    // Note that due to how ComputeType works (only assign the type to the node if the
2680
    // subs' types are valid) this would fail if any node of tree is badly typed.
2681
125
    if (!tl_node.IsValidTopLevel()) return {};
2682
125
    return tl_node;
2683
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
2300
616
{
2301
    // The two integers are used to hold state for thresh()
2302
616
    std::vector<std::tuple<DecodeContext, int64_t, int64_t>> to_parse;
2303
616
    std::vector<Node<Key>> constructed;
2304
2305
    // This is the top level, so we assume the type is B
2306
    // (in particular, disallowing top level W expressions)
2307
616
    to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2308
2309
1.33M
    while (!to_parse.empty()) {
2310
        // Exit early if the Miniscript is not going to be valid.
2311
1.33M
        if (!constructed.empty() && !constructed.back().IsValid()) return {};
2312
2313
        // Get the current context we are decoding within
2314
1.33M
        auto [cur_context, n, k] = to_parse.back();
2315
1.33M
        to_parse.pop_back();
2316
2317
1.33M
        switch(cur_context) {
2318
663k
        case DecodeContext::SINGLE_BKV_EXPR: {
2319
663k
            if (in >= last) return {};
2320
2321
            // Constants
2322
663k
            if (in[0].first == OP_1) {
2323
3
                ++in;
2324
3
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1);
2325
3
                break;
2326
3
            }
2327
663k
            if (in[0].first == OP_0) {
2328
193
                ++in;
2329
193
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
2330
193
                break;
2331
193
            }
2332
            // Public keys
2333
663k
            if (in[0].second.size() == 33 || in[0].second.size() == 32) {
2334
917
                auto key = ctx.FromPKBytes(in[0].second.begin(), in[0].second.end());
2335
917
                if (!key) return {};
2336
915
                ++in;
2337
915
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_K, Vector(std::move(*key)));
2338
915
                break;
2339
917
            }
2340
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) {
2341
298
                auto key = ctx.FromPKHBytes(in[2].second.begin(), in[2].second.end());
2342
298
                if (!key) return {};
2343
296
                in += 5;
2344
296
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_H, Vector(std::move(*key)));
2345
296
                break;
2346
298
            }
2347
            // Time locks
2348
662k
            std::optional<int64_t> num;
2349
662k
            if (last - in >= 2 && in[0].first == OP_CHECKSEQUENCEVERIFY && (num = ParseScriptNumber(in[1]))) {
2350
188
                in += 2;
2351
188
                if (*num < 1 || *num > 0x7FFFFFFFL) return {};
2352
188
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num);
2353
188
                break;
2354
188
            }
2355
662k
            if (last - in >= 2 && in[0].first == OP_CHECKLOCKTIMEVERIFY && (num = ParseScriptNumber(in[1]))) {
2356
230
                in += 2;
2357
230
                if (num < 1 || num > 0x7FFFFFFFL) return {};
2358
230
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num);
2359
230
                break;
2360
230
            }
2361
            // Hashes
2362
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) {
2363
153
                if (in[2].first == OP_SHA256 && in[1].second.size() == 32) {
2364
28
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, in[1].second);
2365
28
                    in += 7;
2366
28
                    break;
2367
125
                } else if (in[2].first == OP_RIPEMD160 && in[1].second.size() == 20) {
2368
36
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::RIPEMD160, in[1].second);
2369
36
                    in += 7;
2370
36
                    break;
2371
89
                } else if (in[2].first == OP_HASH256 && in[1].second.size() == 32) {
2372
48
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, in[1].second);
2373
48
                    in += 7;
2374
48
                    break;
2375
48
                } else if (in[2].first == OP_HASH160 && in[1].second.size() == 20) {
2376
41
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, in[1].second);
2377
41
                    in += 7;
2378
41
                    break;
2379
41
                }
2380
153
            }
2381
            // Multi
2382
661k
            if (last - in >= 3 && in[0].first == OP_CHECKMULTISIG) {
2383
90
                if (IsTapscript(ctx.MsContext())) return {};
2384
90
                std::vector<Key> keys;
2385
90
                const auto n = ParseScriptNumber(in[1]);
2386
90
                if (!n || last - in < 3 + *n) return {};
2387
90
                if (*n < 1 || *n > 20) return {};
2388
312
                for (int i = 0; i < *n; ++i) {
2389
222
                    if (in[2 + i].second.size() != 33) return {};
2390
222
                    auto key = ctx.FromPKBytes(in[2 + i].second.begin(), in[2 + i].second.end());
2391
222
                    if (!key) return {};
2392
222
                    keys.push_back(std::move(*key));
2393
222
                }
2394
90
                const auto k = ParseScriptNumber(in[2 + *n]);
2395
90
                if (!k || *k < 1 || *k > *n) return {};
2396
90
                in += 3 + *n;
2397
90
                std::reverse(keys.begin(), keys.end());
2398
90
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), *k);
2399
90
                break;
2400
90
            }
2401
            // Tapscript's equivalent of multi
2402
661k
            if (last - in >= 4 && in[0].first == OP_NUMEQUAL) {
2403
4
                if (!IsTapscript(ctx.MsContext())) return {};
2404
                // The necessary threshold of signatures.
2405
4
                const auto k = ParseScriptNumber(in[1]);
2406
4
                if (!k) return {};
2407
4
                if (*k < 1 || *k > MAX_PUBKEYS_PER_MULTI_A) return {};
2408
4
                if (last - in < 2 + *k * 2) return {};
2409
4
                std::vector<Key> keys;
2410
4
                keys.reserve(*k);
2411
                // Walk through the expected (pubkey, CHECKSIG[ADD]) pairs.
2412
8
                for (int pos = 2;; pos += 2) {
2413
8
                    if (last - in < pos + 2) return {};
2414
                    // Make sure it's indeed an x-only pubkey and a CHECKSIG[ADD], then parse the key.
2415
8
                    if (in[pos].first != OP_CHECKSIGADD && in[pos].first != OP_CHECKSIG) return {};
2416
8
                    if (in[pos + 1].second.size() != 32) return {};
2417
8
                    auto key = ctx.FromPKBytes(in[pos + 1].second.begin(), in[pos + 1].second.end());
2418
8
                    if (!key) return {};
2419
8
                    keys.push_back(std::move(*key));
2420
                    // Make sure early we don't parse an arbitrary large expression.
2421
8
                    if (keys.size() > MAX_PUBKEYS_PER_MULTI_A) return {};
2422
                    // OP_CHECKSIG means it was the last one to parse.
2423
8
                    if (in[pos].first == OP_CHECKSIG) break;
2424
8
                }
2425
4
                if (keys.size() < (size_t)*k) return {};
2426
4
                in += 2 + keys.size() * 2;
2427
4
                std::reverse(keys.begin(), keys.end());
2428
4
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), *k);
2429
4
                break;
2430
4
            }
2431
            /** In the following wrappers, we only need to push SINGLE_BKV_EXPR rather
2432
             * than BKV_EXPR, because and_v commutes with these wrappers. For example,
2433
             * c:and_v(X,Y) produces the same script as and_v(X,c:Y). */
2434
            // c: wrapper
2435
661k
            if (in[0].first == OP_CHECKSIG) {
2436
1.19k
                ++in;
2437
1.19k
                to_parse.emplace_back(DecodeContext::CHECK, -1, -1);
2438
1.19k
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2439
1.19k
                break;
2440
1.19k
            }
2441
            // v: wrapper
2442
660k
            if (in[0].first == OP_VERIFY) {
2443
490
                ++in;
2444
490
                to_parse.emplace_back(DecodeContext::VERIFY, -1, -1);
2445
490
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2446
490
                break;
2447
490
            }
2448
            // n: wrapper
2449
659k
            if (in[0].first == OP_0NOTEQUAL) {
2450
659k
                ++in;
2451
659k
                to_parse.emplace_back(DecodeContext::ZERO_NOTEQUAL, -1, -1);
2452
659k
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2453
659k
                break;
2454
659k
            }
2455
            // Thresh
2456
761
            if (last - in >= 3 && in[0].first == OP_EQUAL && (num = ParseScriptNumber(in[1]))) {
2457
174
                if (*num < 1) return {};
2458
174
                in += 2;
2459
174
                to_parse.emplace_back(DecodeContext::THRESH_W, 0, *num);
2460
174
                break;
2461
174
            }
2462
            // OP_ENDIF can be WRAP_J, WRAP_D, ANDOR, OR_C, OR_D, or OR_I
2463
587
            if (in[0].first == OP_ENDIF) {
2464
383
                ++in;
2465
383
                to_parse.emplace_back(DecodeContext::ENDIF, -1, -1);
2466
383
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2467
383
                break;
2468
383
            }
2469
            /** In and_b and or_b nodes, we only look for SINGLE_BKV_EXPR, because
2470
             * or_b(and_v(X,Y),Z) has script [X] [Y] [Z] OP_BOOLOR, the same as
2471
             * and_v(X,or_b(Y,Z)). In this example, the former of these is invalid as
2472
             * miniscript, while the latter is valid. So we leave the and_v "outside"
2473
             * while decoding. */
2474
            // and_b
2475
204
            if (in[0].first == OP_BOOLAND) {
2476
176
                ++in;
2477
176
                to_parse.emplace_back(DecodeContext::AND_B, -1, -1);
2478
176
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2479
176
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2480
176
                break;
2481
176
            }
2482
            // or_b
2483
28
            if (in[0].first == OP_BOOLOR) {
2484
20
                ++in;
2485
20
                to_parse.emplace_back(DecodeContext::OR_B, -1, -1);
2486
20
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2487
20
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2488
20
                break;
2489
20
            }
2490
            // Unrecognised expression
2491
8
            return {};
2492
28
        }
2493
2.32k
        case DecodeContext::BKV_EXPR: {
2494
2.32k
            to_parse.emplace_back(DecodeContext::MAYBE_AND_V, -1, -1);
2495
2.32k
            to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2496
2.32k
            break;
2497
28
        }
2498
614
        case DecodeContext::W_EXPR: {
2499
            // a: wrapper
2500
614
            if (in >= last) return {};
2501
614
            if (in[0].first == OP_FROMALTSTACK) {
2502
334
                ++in;
2503
334
                to_parse.emplace_back(DecodeContext::ALT, -1, -1);
2504
334
            } else {
2505
280
                to_parse.emplace_back(DecodeContext::SWAP, -1, -1);
2506
280
            }
2507
614
            to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2508
614
            break;
2509
614
        }
2510
2.31k
        case DecodeContext::MAYBE_AND_V: {
2511
            // If we reach a potential AND_V top-level, check if the next part of the script could be another AND_V child
2512
            // These op-codes cannot end any well-formed miniscript so cannot be used in an and_v node.
2513
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) {
2514
441
                to_parse.emplace_back(DecodeContext::AND_V, -1, -1);
2515
                // BKV_EXPR can contain more AND_V nodes
2516
441
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2517
441
            }
2518
2.31k
            break;
2519
614
        }
2520
280
        case DecodeContext::SWAP: {
2521
280
            if (in >= last || in[0].first != OP_SWAP || constructed.empty()) return {};
2522
280
            ++in;
2523
280
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S, Vector(std::move(constructed.back()))};
2524
280
            break;
2525
280
        }
2526
334
        case DecodeContext::ALT: {
2527
334
            if (in >= last || in[0].first != OP_TOALTSTACK || constructed.empty()) return {};
2528
334
            ++in;
2529
334
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A, Vector(std::move(constructed.back()))};
2530
334
            break;
2531
334
        }
2532
1.19k
        case DecodeContext::CHECK: {
2533
1.19k
            if (constructed.empty()) return {};
2534
1.19k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(std::move(constructed.back()))};
2535
1.19k
            break;
2536
1.19k
        }
2537
52
        case DecodeContext::DUP_IF: {
2538
52
            if (constructed.empty()) return {};
2539
52
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D, Vector(std::move(constructed.back()))};
2540
52
            break;
2541
52
        }
2542
490
        case DecodeContext::VERIFY: {
2543
490
            if (constructed.empty()) return {};
2544
490
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V, Vector(std::move(constructed.back()))};
2545
490
            break;
2546
490
        }
2547
0
        case DecodeContext::NON_ZERO: {
2548
0
            if (constructed.empty()) return {};
2549
0
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J, Vector(std::move(constructed.back()))};
2550
0
            break;
2551
0
        }
2552
659k
        case DecodeContext::ZERO_NOTEQUAL: {
2553
659k
            if (constructed.empty()) return {};
2554
659k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N, Vector(std::move(constructed.back()))};
2555
659k
            break;
2556
659k
        }
2557
439
        case DecodeContext::AND_V: {
2558
439
            if (constructed.size() < 2) return {};
2559
439
            BuildBack(ctx.MsContext(), Fragment::AND_V, constructed, /*reverse=*/true);
2560
439
            break;
2561
439
        }
2562
176
        case DecodeContext::AND_B: {
2563
176
            if (constructed.size() < 2) return {};
2564
176
            BuildBack(ctx.MsContext(), Fragment::AND_B, constructed, /*reverse=*/true);
2565
176
            break;
2566
176
        }
2567
20
        case DecodeContext::OR_B: {
2568
20
            if (constructed.size() < 2) return {};
2569
20
            BuildBack(ctx.MsContext(), Fragment::OR_B, constructed, /*reverse=*/true);
2570
20
            break;
2571
20
        }
2572
16
        case DecodeContext::OR_C: {
2573
16
            if (constructed.size() < 2) return {};
2574
16
            BuildBack(ctx.MsContext(), Fragment::OR_C, constructed, /*reverse=*/true);
2575
16
            break;
2576
16
        }
2577
43
        case DecodeContext::OR_D: {
2578
43
            if (constructed.size() < 2) return {};
2579
43
            BuildBack(ctx.MsContext(), Fragment::OR_D, constructed, /*reverse=*/true);
2580
43
            break;
2581
43
        }
2582
83
        case DecodeContext::ANDOR: {
2583
83
            if (constructed.size() < 3) return {};
2584
83
            Node left{std::move(constructed.back())};
2585
83
            constructed.pop_back();
2586
83
            Node right{std::move(constructed.back())};
2587
83
            constructed.pop_back();
2588
83
            Node mid{std::move(constructed.back())};
2589
83
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR, Vector(std::move(left), std::move(mid), std::move(right))};
2590
83
            break;
2591
83
        }
2592
592
        case DecodeContext::THRESH_W: {
2593
592
            if (in >= last) return {};
2594
592
            if (in[0].first == OP_ADD) {
2595
418
                ++in;
2596
418
                to_parse.emplace_back(DecodeContext::THRESH_W, n+1, k);
2597
418
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2598
418
            } else {
2599
174
                to_parse.emplace_back(DecodeContext::THRESH_E, n+1, k);
2600
                // All children of thresh have type modifier d, so cannot be and_v
2601
174
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2602
174
            }
2603
592
            break;
2604
592
        }
2605
174
        case DecodeContext::THRESH_E: {
2606
174
            if (k < 1 || k > n || constructed.size() < static_cast<size_t>(n)) return {};
2607
174
            std::vector<Node<Key>> subs;
2608
766
            for (int i = 0; i < n; ++i) {
2609
592
                Node sub{std::move(constructed.back())};
2610
592
                constructed.pop_back();
2611
592
                subs.push_back(std::move(sub));
2612
592
            }
2613
174
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs), k);
2614
174
            break;
2615
174
        }
2616
382
        case DecodeContext::ENDIF: {
2617
382
            if (in >= last) return {};
2618
2619
            // could be andor or or_i
2620
382
            if (in[0].first == OP_ELSE) {
2621
271
                ++in;
2622
271
                to_parse.emplace_back(DecodeContext::ENDIF_ELSE, -1, -1);
2623
271
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2624
271
            }
2625
            // could be j: or d: wrapper
2626
111
            else if (in[0].first == OP_IF) {
2627
52
                if (last - in >= 2 && in[1].first == OP_DUP) {
2628
52
                    in += 2;
2629
52
                    to_parse.emplace_back(DecodeContext::DUP_IF, -1, -1);
2630
52
                } else if (last - in >= 3 && in[1].first == OP_0NOTEQUAL && in[2].first == OP_SIZE) {
2631
0
                    in += 3;
2632
0
                    to_parse.emplace_back(DecodeContext::NON_ZERO, -1, -1);
2633
0
                }
2634
0
                else {
2635
0
                    return {};
2636
0
                }
2637
            // could be or_c or or_d
2638
59
            } else if (in[0].first == OP_NOTIF) {
2639
59
                ++in;
2640
59
                to_parse.emplace_back(DecodeContext::ENDIF_NOTIF, -1, -1);
2641
59
            }
2642
0
            else {
2643
0
                return {};
2644
0
            }
2645
382
            break;
2646
382
        }
2647
382
        case DecodeContext::ENDIF_NOTIF: {
2648
59
            if (in >= last) return {};
2649
59
            if (in[0].first == OP_IFDUP) {
2650
43
                ++in;
2651
43
                to_parse.emplace_back(DecodeContext::OR_D, -1, -1);
2652
43
            } else {
2653
16
                to_parse.emplace_back(DecodeContext::OR_C, -1, -1);
2654
16
            }
2655
            // or_c and or_d both require X to have type modifier d so, can't contain and_v
2656
59
            to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2657
59
            break;
2658
59
        }
2659
271
        case DecodeContext::ENDIF_ELSE: {
2660
271
            if (in >= last) return {};
2661
271
            if (in[0].first == OP_IF) {
2662
188
                ++in;
2663
188
                BuildBack(ctx.MsContext(), Fragment::OR_I, constructed, /*reverse=*/true);
2664
188
            } else if (in[0].first == OP_NOTIF) {
2665
83
                ++in;
2666
83
                to_parse.emplace_back(DecodeContext::ANDOR, -1, -1);
2667
                // andor requires X to have type modifier d, so it can't be and_v
2668
83
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2669
83
            } else {
2670
0
                return {};
2671
0
            }
2672
271
            break;
2673
271
        }
2674
1.33M
        }
2675
1.33M
    }
2676
604
    if (constructed.size() != 1) return {};
2677
604
    Node tl_node{std::move(constructed.front())};
2678
604
    tl_node.DuplicateKeyCheck(ctx);
2679
    // Note that due to how ComputeType works (only assign the type to the node if the
2680
    // subs' types are valid) this would fail if any node of tree is badly typed.
2681
604
    if (!tl_node.IsValidTopLevel()) return {};
2682
603
    return tl_node;
2683
604
}
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
2300
3.16k
{
2301
    // The two integers are used to hold state for thresh()
2302
3.16k
    std::vector<std::tuple<DecodeContext, int64_t, int64_t>> to_parse;
2303
3.16k
    std::vector<Node<Key>> constructed;
2304
2305
    // This is the top level, so we assume the type is B
2306
    // (in particular, disallowing top level W expressions)
2307
3.16k
    to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2308
2309
14.5M
    while (!to_parse.empty()) {
2310
        // Exit early if the Miniscript is not going to be valid.
2311
14.5M
        if (!constructed.empty() && !constructed.back().IsValid()) return {};
2312
2313
        // Get the current context we are decoding within
2314
14.5M
        auto [cur_context, n, k] = to_parse.back();
2315
14.5M
        to_parse.pop_back();
2316
2317
14.5M
        switch(cur_context) {
2318
7.25M
        case DecodeContext::SINGLE_BKV_EXPR: {
2319
7.25M
            if (in >= last) return {};
2320
2321
            // Constants
2322
7.25M
            if (in[0].first == OP_1) {
2323
0
                ++in;
2324
0
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1);
2325
0
                break;
2326
0
            }
2327
7.25M
            if (in[0].first == OP_0) {
2328
0
                ++in;
2329
0
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
2330
0
                break;
2331
0
            }
2332
            // Public keys
2333
7.25M
            if (in[0].second.size() == 33 || in[0].second.size() == 32) {
2334
2.36k
                auto key = ctx.FromPKBytes(in[0].second.begin(), in[0].second.end());
2335
2.36k
                if (!key) return {};
2336
2.36k
                ++in;
2337
2.36k
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_K, Vector(std::move(*key)));
2338
2.36k
                break;
2339
2.36k
            }
2340
7.25M
            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) {
2341
224
                auto key = ctx.FromPKHBytes(in[2].second.begin(), in[2].second.end());
2342
224
                if (!key) return {};
2343
224
                in += 5;
2344
224
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_H, Vector(std::move(*key)));
2345
224
                break;
2346
224
            }
2347
            // Time locks
2348
7.25M
            std::optional<int64_t> num;
2349
7.25M
            if (last - in >= 2 && in[0].first == OP_CHECKSEQUENCEVERIFY && (num = ParseScriptNumber(in[1]))) {
2350
60
                in += 2;
2351
60
                if (*num < 1 || *num > 0x7FFFFFFFL) return {};
2352
60
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num);
2353
60
                break;
2354
60
            }
2355
7.25M
            if (last - in >= 2 && in[0].first == OP_CHECKLOCKTIMEVERIFY && (num = ParseScriptNumber(in[1]))) {
2356
428
                in += 2;
2357
428
                if (num < 1 || num > 0x7FFFFFFFL) return {};
2358
428
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num);
2359
428
                break;
2360
428
            }
2361
            // Hashes
2362
7.25M
            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) {
2363
12
                if (in[2].first == OP_SHA256 && in[1].second.size() == 32) {
2364
0
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, in[1].second);
2365
0
                    in += 7;
2366
0
                    break;
2367
12
                } else if (in[2].first == OP_RIPEMD160 && in[1].second.size() == 20) {
2368
0
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::RIPEMD160, in[1].second);
2369
0
                    in += 7;
2370
0
                    break;
2371
12
                } else if (in[2].first == OP_HASH256 && in[1].second.size() == 32) {
2372
12
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, in[1].second);
2373
12
                    in += 7;
2374
12
                    break;
2375
12
                } else if (in[2].first == OP_HASH160 && in[1].second.size() == 20) {
2376
0
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, in[1].second);
2377
0
                    in += 7;
2378
0
                    break;
2379
0
                }
2380
12
            }
2381
            // Multi
2382
7.25M
            if (last - in >= 3 && in[0].first == OP_CHECKMULTISIG) {
2383
0
                if (IsTapscript(ctx.MsContext())) return {};
2384
0
                std::vector<Key> keys;
2385
0
                const auto n = ParseScriptNumber(in[1]);
2386
0
                if (!n || last - in < 3 + *n) return {};
2387
0
                if (*n < 1 || *n > 20) return {};
2388
0
                for (int i = 0; i < *n; ++i) {
2389
0
                    if (in[2 + i].second.size() != 33) return {};
2390
0
                    auto key = ctx.FromPKBytes(in[2 + i].second.begin(), in[2 + i].second.end());
2391
0
                    if (!key) return {};
2392
0
                    keys.push_back(std::move(*key));
2393
0
                }
2394
0
                const auto k = ParseScriptNumber(in[2 + *n]);
2395
0
                if (!k || *k < 1 || *k > *n) return {};
2396
0
                in += 3 + *n;
2397
0
                std::reverse(keys.begin(), keys.end());
2398
0
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), *k);
2399
0
                break;
2400
0
            }
2401
            // Tapscript's equivalent of multi
2402
7.25M
            if (last - in >= 4 && in[0].first == OP_NUMEQUAL) {
2403
772
                if (!IsTapscript(ctx.MsContext())) return {};
2404
                // The necessary threshold of signatures.
2405
772
                const auto k = ParseScriptNumber(in[1]);
2406
772
                if (!k) return {};
2407
772
                if (*k < 1 || *k > MAX_PUBKEYS_PER_MULTI_A) return {};
2408
772
                if (last - in < 2 + *k * 2) return {};
2409
772
                std::vector<Key> keys;
2410
772
                keys.reserve(*k);
2411
                // Walk through the expected (pubkey, CHECKSIG[ADD]) pairs.
2412
90.5k
                for (int pos = 2;; pos += 2) {
2413
90.5k
                    if (last - in < pos + 2) return {};
2414
                    // Make sure it's indeed an x-only pubkey and a CHECKSIG[ADD], then parse the key.
2415
90.5k
                    if (in[pos].first != OP_CHECKSIGADD && in[pos].first != OP_CHECKSIG) return {};
2416
90.5k
                    if (in[pos + 1].second.size() != 32) return {};
2417
90.5k
                    auto key = ctx.FromPKBytes(in[pos + 1].second.begin(), in[pos + 1].second.end());
2418
90.5k
                    if (!key) return {};
2419
90.5k
                    keys.push_back(std::move(*key));
2420
                    // Make sure early we don't parse an arbitrary large expression.
2421
90.5k
                    if (keys.size() > MAX_PUBKEYS_PER_MULTI_A) return {};
2422
                    // OP_CHECKSIG means it was the last one to parse.
2423
90.5k
                    if (in[pos].first == OP_CHECKSIG) break;
2424
90.5k
                }
2425
772
                if (keys.size() < (size_t)*k) return {};
2426
772
                in += 2 + keys.size() * 2;
2427
772
                std::reverse(keys.begin(), keys.end());
2428
772
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), *k);
2429
772
                break;
2430
772
            }
2431
            /** In the following wrappers, we only need to push SINGLE_BKV_EXPR rather
2432
             * than BKV_EXPR, because and_v commutes with these wrappers. For example,
2433
             * c:and_v(X,Y) produces the same script as and_v(X,c:Y). */
2434
            // c: wrapper
2435
7.25M
            if (in[0].first == OP_CHECKSIG) {
2436
2.58k
                ++in;
2437
2.58k
                to_parse.emplace_back(DecodeContext::CHECK, -1, -1);
2438
2.58k
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2439
2.58k
                break;
2440
2.58k
            }
2441
            // v: wrapper
2442
7.24M
            if (in[0].first == OP_VERIFY) {
2443
558
                ++in;
2444
558
                to_parse.emplace_back(DecodeContext::VERIFY, -1, -1);
2445
558
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2446
558
                break;
2447
558
            }
2448
            // n: wrapper
2449
7.24M
            if (in[0].first == OP_0NOTEQUAL) {
2450
7.24M
                ++in;
2451
7.24M
                to_parse.emplace_back(DecodeContext::ZERO_NOTEQUAL, -1, -1);
2452
7.24M
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2453
7.24M
                break;
2454
7.24M
            }
2455
            // Thresh
2456
122
            if (last - in >= 3 && in[0].first == OP_EQUAL && (num = ParseScriptNumber(in[1]))) {
2457
28
                if (*num < 1) return {};
2458
28
                in += 2;
2459
28
                to_parse.emplace_back(DecodeContext::THRESH_W, 0, *num);
2460
28
                break;
2461
28
            }
2462
            // OP_ENDIF can be WRAP_J, WRAP_D, ANDOR, OR_C, OR_D, or OR_I
2463
94
            if (in[0].first == OP_ENDIF) {
2464
6
                ++in;
2465
6
                to_parse.emplace_back(DecodeContext::ENDIF, -1, -1);
2466
6
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2467
6
                break;
2468
6
            }
2469
            /** In and_b and or_b nodes, we only look for SINGLE_BKV_EXPR, because
2470
             * or_b(and_v(X,Y),Z) has script [X] [Y] [Z] OP_BOOLOR, the same as
2471
             * and_v(X,or_b(Y,Z)). In this example, the former of these is invalid as
2472
             * miniscript, while the latter is valid. So we leave the and_v "outside"
2473
             * while decoding. */
2474
            // and_b
2475
88
            if (in[0].first == OP_BOOLAND) {
2476
88
                ++in;
2477
88
                to_parse.emplace_back(DecodeContext::AND_B, -1, -1);
2478
88
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2479
88
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2480
88
                break;
2481
88
            }
2482
            // or_b
2483
0
            if (in[0].first == OP_BOOLOR) {
2484
0
                ++in;
2485
0
                to_parse.emplace_back(DecodeContext::OR_B, -1, -1);
2486
0
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2487
0
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2488
0
                break;
2489
0
            }
2490
            // Unrecognised expression
2491
0
            return {};
2492
0
        }
2493
3.86k
        case DecodeContext::BKV_EXPR: {
2494
3.86k
            to_parse.emplace_back(DecodeContext::MAYBE_AND_V, -1, -1);
2495
3.86k
            to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2496
3.86k
            break;
2497
0
        }
2498
144
        case DecodeContext::W_EXPR: {
2499
            // a: wrapper
2500
144
            if (in >= last) return {};
2501
144
            if (in[0].first == OP_FROMALTSTACK) {
2502
116
                ++in;
2503
116
                to_parse.emplace_back(DecodeContext::ALT, -1, -1);
2504
116
            } else {
2505
28
                to_parse.emplace_back(DecodeContext::SWAP, -1, -1);
2506
28
            }
2507
144
            to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2508
144
            break;
2509
144
        }
2510
3.86k
        case DecodeContext::MAYBE_AND_V: {
2511
            // If we reach a potential AND_V top-level, check if the next part of the script could be another AND_V child
2512
            // These op-codes cannot end any well-formed miniscript so cannot be used in an and_v node.
2513
3.86k
            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) {
2514
552
                to_parse.emplace_back(DecodeContext::AND_V, -1, -1);
2515
                // BKV_EXPR can contain more AND_V nodes
2516
552
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2517
552
            }
2518
3.86k
            break;
2519
144
        }
2520
28
        case DecodeContext::SWAP: {
2521
28
            if (in >= last || in[0].first != OP_SWAP || constructed.empty()) return {};
2522
28
            ++in;
2523
28
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S, Vector(std::move(constructed.back()))};
2524
28
            break;
2525
28
        }
2526
116
        case DecodeContext::ALT: {
2527
116
            if (in >= last || in[0].first != OP_TOALTSTACK || constructed.empty()) return {};
2528
116
            ++in;
2529
116
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A, Vector(std::move(constructed.back()))};
2530
116
            break;
2531
116
        }
2532
2.58k
        case DecodeContext::CHECK: {
2533
2.58k
            if (constructed.empty()) return {};
2534
2.58k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(std::move(constructed.back()))};
2535
2.58k
            break;
2536
2.58k
        }
2537
6
        case DecodeContext::DUP_IF: {
2538
6
            if (constructed.empty()) return {};
2539
6
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D, Vector(std::move(constructed.back()))};
2540
6
            break;
2541
6
        }
2542
558
        case DecodeContext::VERIFY: {
2543
558
            if (constructed.empty()) return {};
2544
558
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V, Vector(std::move(constructed.back()))};
2545
558
            break;
2546
558
        }
2547
0
        case DecodeContext::NON_ZERO: {
2548
0
            if (constructed.empty()) return {};
2549
0
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J, Vector(std::move(constructed.back()))};
2550
0
            break;
2551
0
        }
2552
7.24M
        case DecodeContext::ZERO_NOTEQUAL: {
2553
7.24M
            if (constructed.empty()) return {};
2554
7.24M
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N, Vector(std::move(constructed.back()))};
2555
7.24M
            break;
2556
7.24M
        }
2557
552
        case DecodeContext::AND_V: {
2558
552
            if (constructed.size() < 2) return {};
2559
552
            BuildBack(ctx.MsContext(), Fragment::AND_V, constructed, /*reverse=*/true);
2560
552
            break;
2561
552
        }
2562
88
        case DecodeContext::AND_B: {
2563
88
            if (constructed.size() < 2) return {};
2564
88
            BuildBack(ctx.MsContext(), Fragment::AND_B, constructed, /*reverse=*/true);
2565
88
            break;
2566
88
        }
2567
0
        case DecodeContext::OR_B: {
2568
0
            if (constructed.size() < 2) return {};
2569
0
            BuildBack(ctx.MsContext(), Fragment::OR_B, constructed, /*reverse=*/true);
2570
0
            break;
2571
0
        }
2572
0
        case DecodeContext::OR_C: {
2573
0
            if (constructed.size() < 2) return {};
2574
0
            BuildBack(ctx.MsContext(), Fragment::OR_C, constructed, /*reverse=*/true);
2575
0
            break;
2576
0
        }
2577
0
        case DecodeContext::OR_D: {
2578
0
            if (constructed.size() < 2) return {};
2579
0
            BuildBack(ctx.MsContext(), Fragment::OR_D, constructed, /*reverse=*/true);
2580
0
            break;
2581
0
        }
2582
0
        case DecodeContext::ANDOR: {
2583
0
            if (constructed.size() < 3) return {};
2584
0
            Node left{std::move(constructed.back())};
2585
0
            constructed.pop_back();
2586
0
            Node right{std::move(constructed.back())};
2587
0
            constructed.pop_back();
2588
0
            Node mid{std::move(constructed.back())};
2589
0
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR, Vector(std::move(left), std::move(mid), std::move(right))};
2590
0
            break;
2591
0
        }
2592
84
        case DecodeContext::THRESH_W: {
2593
84
            if (in >= last) return {};
2594
84
            if (in[0].first == OP_ADD) {
2595
56
                ++in;
2596
56
                to_parse.emplace_back(DecodeContext::THRESH_W, n+1, k);
2597
56
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2598
56
            } else {
2599
28
                to_parse.emplace_back(DecodeContext::THRESH_E, n+1, k);
2600
                // All children of thresh have type modifier d, so cannot be and_v
2601
28
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2602
28
            }
2603
84
            break;
2604
84
        }
2605
28
        case DecodeContext::THRESH_E: {
2606
28
            if (k < 1 || k > n || constructed.size() < static_cast<size_t>(n)) return {};
2607
28
            std::vector<Node<Key>> subs;
2608
112
            for (int i = 0; i < n; ++i) {
2609
84
                Node sub{std::move(constructed.back())};
2610
84
                constructed.pop_back();
2611
84
                subs.push_back(std::move(sub));
2612
84
            }
2613
28
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs), k);
2614
28
            break;
2615
28
        }
2616
6
        case DecodeContext::ENDIF: {
2617
6
            if (in >= last) return {};
2618
2619
            // could be andor or or_i
2620
6
            if (in[0].first == OP_ELSE) {
2621
0
                ++in;
2622
0
                to_parse.emplace_back(DecodeContext::ENDIF_ELSE, -1, -1);
2623
0
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2624
0
            }
2625
            // could be j: or d: wrapper
2626
6
            else if (in[0].first == OP_IF) {
2627
6
                if (last - in >= 2 && in[1].first == OP_DUP) {
2628
6
                    in += 2;
2629
6
                    to_parse.emplace_back(DecodeContext::DUP_IF, -1, -1);
2630
6
                } else if (last - in >= 3 && in[1].first == OP_0NOTEQUAL && in[2].first == OP_SIZE) {
2631
0
                    in += 3;
2632
0
                    to_parse.emplace_back(DecodeContext::NON_ZERO, -1, -1);
2633
0
                }
2634
0
                else {
2635
0
                    return {};
2636
0
                }
2637
            // could be or_c or or_d
2638
6
            } else if (in[0].first == OP_NOTIF) {
2639
0
                ++in;
2640
0
                to_parse.emplace_back(DecodeContext::ENDIF_NOTIF, -1, -1);
2641
0
            }
2642
0
            else {
2643
0
                return {};
2644
0
            }
2645
6
            break;
2646
6
        }
2647
6
        case DecodeContext::ENDIF_NOTIF: {
2648
0
            if (in >= last) return {};
2649
0
            if (in[0].first == OP_IFDUP) {
2650
0
                ++in;
2651
0
                to_parse.emplace_back(DecodeContext::OR_D, -1, -1);
2652
0
            } else {
2653
0
                to_parse.emplace_back(DecodeContext::OR_C, -1, -1);
2654
0
            }
2655
            // or_c and or_d both require X to have type modifier d so, can't contain and_v
2656
0
            to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2657
0
            break;
2658
0
        }
2659
0
        case DecodeContext::ENDIF_ELSE: {
2660
0
            if (in >= last) return {};
2661
0
            if (in[0].first == OP_IF) {
2662
0
                ++in;
2663
0
                BuildBack(ctx.MsContext(), Fragment::OR_I, constructed, /*reverse=*/true);
2664
0
            } else if (in[0].first == OP_NOTIF) {
2665
0
                ++in;
2666
0
                to_parse.emplace_back(DecodeContext::ANDOR, -1, -1);
2667
                // andor requires X to have type modifier d, so it can't be and_v
2668
0
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2669
0
            } else {
2670
0
                return {};
2671
0
            }
2672
0
            break;
2673
0
        }
2674
14.5M
        }
2675
14.5M
    }
2676
3.16k
    if (constructed.size() != 1) return {};
2677
3.16k
    Node tl_node{std::move(constructed.front())};
2678
3.16k
    tl_node.DuplicateKeyCheck(ctx);
2679
    // Note that due to how ComputeType works (only assign the type to the node if the
2680
    // subs' types are valid) this would fail if any node of tree is badly typed.
2681
3.16k
    if (!tl_node.IsValidTopLevel()) return {};
2682
3.16k
    return tl_node;
2683
3.16k
}
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
2300
237
{
2301
    // The two integers are used to hold state for thresh()
2302
237
    std::vector<std::tuple<DecodeContext, int64_t, int64_t>> to_parse;
2303
237
    std::vector<Node<Key>> constructed;
2304
2305
    // This is the top level, so we assume the type is B
2306
    // (in particular, disallowing top level W expressions)
2307
237
    to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2308
2309
9.23k
    while (!to_parse.empty()) {
2310
        // Exit early if the Miniscript is not going to be valid.
2311
9.00k
        if (!constructed.empty() && !constructed.back().IsValid()) return {};
2312
2313
        // Get the current context we are decoding within
2314
9.00k
        auto [cur_context, n, k] = to_parse.back();
2315
9.00k
        to_parse.pop_back();
2316
2317
9.00k
        switch(cur_context) {
2318
2.61k
        case DecodeContext::SINGLE_BKV_EXPR: {
2319
2.61k
            if (in >= last) return {};
2320
2321
            // Constants
2322
2.61k
            if (in[0].first == OP_1) {
2323
0
                ++in;
2324
0
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1);
2325
0
                break;
2326
0
            }
2327
2.61k
            if (in[0].first == OP_0) {
2328
243
                ++in;
2329
243
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
2330
243
                break;
2331
243
            }
2332
            // Public keys
2333
2.37k
            if (in[0].second.size() == 33 || in[0].second.size() == 32) {
2334
475
                auto key = ctx.FromPKBytes(in[0].second.begin(), in[0].second.end());
2335
475
                if (!key) return {};
2336
474
                ++in;
2337
474
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_K, Vector(std::move(*key)));
2338
474
                break;
2339
475
            }
2340
1.90k
            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) {
2341
62
                auto key = ctx.FromPKHBytes(in[2].second.begin(), in[2].second.end());
2342
62
                if (!key) return {};
2343
61
                in += 5;
2344
61
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_H, Vector(std::move(*key)));
2345
61
                break;
2346
62
            }
2347
            // Time locks
2348
1.83k
            std::optional<int64_t> num;
2349
1.83k
            if (last - in >= 2 && in[0].first == OP_CHECKSEQUENCEVERIFY && (num = ParseScriptNumber(in[1]))) {
2350
87
                in += 2;
2351
87
                if (*num < 1 || *num > 0x7FFFFFFFL) return {};
2352
87
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num);
2353
87
                break;
2354
87
            }
2355
1.75k
            if (last - in >= 2 && in[0].first == OP_CHECKLOCKTIMEVERIFY && (num = ParseScriptNumber(in[1]))) {
2356
252
                in += 2;
2357
252
                if (num < 1 || num > 0x7FFFFFFFL) return {};
2358
252
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num);
2359
252
                break;
2360
252
            }
2361
            // Hashes
2362
1.49k
            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) {
2363
61
                if (in[2].first == OP_SHA256 && in[1].second.size() == 32) {
2364
25
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, in[1].second);
2365
25
                    in += 7;
2366
25
                    break;
2367
36
                } else if (in[2].first == OP_RIPEMD160 && in[1].second.size() == 20) {
2368
12
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::RIPEMD160, in[1].second);
2369
12
                    in += 7;
2370
12
                    break;
2371
24
                } else if (in[2].first == OP_HASH256 && in[1].second.size() == 32) {
2372
12
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, in[1].second);
2373
12
                    in += 7;
2374
12
                    break;
2375
12
                } else if (in[2].first == OP_HASH160 && in[1].second.size() == 20) {
2376
12
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, in[1].second);
2377
12
                    in += 7;
2378
12
                    break;
2379
12
                }
2380
61
            }
2381
            // Multi
2382
1.43k
            if (last - in >= 3 && in[0].first == OP_CHECKMULTISIG) {
2383
24
                if (IsTapscript(ctx.MsContext())) return {};
2384
24
                std::vector<Key> keys;
2385
24
                const auto n = ParseScriptNumber(in[1]);
2386
24
                if (!n || last - in < 3 + *n) return {};
2387
24
                if (*n < 1 || *n > 20) return {};
2388
72
                for (int i = 0; i < *n; ++i) {
2389
48
                    if (in[2 + i].second.size() != 33) return {};
2390
48
                    auto key = ctx.FromPKBytes(in[2 + i].second.begin(), in[2 + i].second.end());
2391
48
                    if (!key) return {};
2392
48
                    keys.push_back(std::move(*key));
2393
48
                }
2394
24
                const auto k = ParseScriptNumber(in[2 + *n]);
2395
24
                if (!k || *k < 1 || *k > *n) return {};
2396
24
                in += 3 + *n;
2397
24
                std::reverse(keys.begin(), keys.end());
2398
24
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), *k);
2399
24
                break;
2400
24
            }
2401
            // Tapscript's equivalent of multi
2402
1.41k
            if (last - in >= 4 && in[0].first == OP_NUMEQUAL) {
2403
0
                if (!IsTapscript(ctx.MsContext())) return {};
2404
                // The necessary threshold of signatures.
2405
0
                const auto k = ParseScriptNumber(in[1]);
2406
0
                if (!k) return {};
2407
0
                if (*k < 1 || *k > MAX_PUBKEYS_PER_MULTI_A) return {};
2408
0
                if (last - in < 2 + *k * 2) return {};
2409
0
                std::vector<Key> keys;
2410
0
                keys.reserve(*k);
2411
                // Walk through the expected (pubkey, CHECKSIG[ADD]) pairs.
2412
0
                for (int pos = 2;; pos += 2) {
2413
0
                    if (last - in < pos + 2) return {};
2414
                    // Make sure it's indeed an x-only pubkey and a CHECKSIG[ADD], then parse the key.
2415
0
                    if (in[pos].first != OP_CHECKSIGADD && in[pos].first != OP_CHECKSIG) return {};
2416
0
                    if (in[pos + 1].second.size() != 32) return {};
2417
0
                    auto key = ctx.FromPKBytes(in[pos + 1].second.begin(), in[pos + 1].second.end());
2418
0
                    if (!key) return {};
2419
0
                    keys.push_back(std::move(*key));
2420
                    // Make sure early we don't parse an arbitrary large expression.
2421
0
                    if (keys.size() > MAX_PUBKEYS_PER_MULTI_A) return {};
2422
                    // OP_CHECKSIG means it was the last one to parse.
2423
0
                    if (in[pos].first == OP_CHECKSIG) break;
2424
0
                }
2425
0
                if (keys.size() < (size_t)*k) return {};
2426
0
                in += 2 + keys.size() * 2;
2427
0
                std::reverse(keys.begin(), keys.end());
2428
0
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), *k);
2429
0
                break;
2430
0
            }
2431
            /** In the following wrappers, we only need to push SINGLE_BKV_EXPR rather
2432
             * than BKV_EXPR, because and_v commutes with these wrappers. For example,
2433
             * c:and_v(X,Y) produces the same script as and_v(X,c:Y). */
2434
            // c: wrapper
2435
1.41k
            if (in[0].first == OP_CHECKSIG) {
2436
534
                ++in;
2437
534
                to_parse.emplace_back(DecodeContext::CHECK, -1, -1);
2438
534
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2439
534
                break;
2440
534
            }
2441
            // v: wrapper
2442
880
            if (in[0].first == OP_VERIFY) {
2443
176
                ++in;
2444
176
                to_parse.emplace_back(DecodeContext::VERIFY, -1, -1);
2445
176
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2446
176
                break;
2447
176
            }
2448
            // n: wrapper
2449
704
            if (in[0].first == OP_0NOTEQUAL) {
2450
274
                ++in;
2451
274
                to_parse.emplace_back(DecodeContext::ZERO_NOTEQUAL, -1, -1);
2452
274
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2453
274
                break;
2454
274
            }
2455
            // Thresh
2456
430
            if (last - in >= 3 && in[0].first == OP_EQUAL && (num = ParseScriptNumber(in[1]))) {
2457
105
                if (*num < 1) return {};
2458
105
                in += 2;
2459
105
                to_parse.emplace_back(DecodeContext::THRESH_W, 0, *num);
2460
105
                break;
2461
105
            }
2462
            // OP_ENDIF can be WRAP_J, WRAP_D, ANDOR, OR_C, OR_D, or OR_I
2463
325
            if (in[0].first == OP_ENDIF) {
2464
316
                ++in;
2465
316
                to_parse.emplace_back(DecodeContext::ENDIF, -1, -1);
2466
316
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2467
316
                break;
2468
316
            }
2469
            /** In and_b and or_b nodes, we only look for SINGLE_BKV_EXPR, because
2470
             * or_b(and_v(X,Y),Z) has script [X] [Y] [Z] OP_BOOLOR, the same as
2471
             * and_v(X,or_b(Y,Z)). In this example, the former of these is invalid as
2472
             * miniscript, while the latter is valid. So we leave the and_v "outside"
2473
             * while decoding. */
2474
            // and_b
2475
9
            if (in[0].first == OP_BOOLAND) {
2476
8
                ++in;
2477
8
                to_parse.emplace_back(DecodeContext::AND_B, -1, -1);
2478
8
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2479
8
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2480
8
                break;
2481
8
            }
2482
            // or_b
2483
1
            if (in[0].first == OP_BOOLOR) {
2484
0
                ++in;
2485
0
                to_parse.emplace_back(DecodeContext::OR_B, -1, -1);
2486
0
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2487
0
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2488
0
                break;
2489
0
            }
2490
            // Unrecognised expression
2491
1
            return {};
2492
1
        }
2493
1.45k
        case DecodeContext::BKV_EXPR: {
2494
1.45k
            to_parse.emplace_back(DecodeContext::MAYBE_AND_V, -1, -1);
2495
1.45k
            to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2496
1.45k
            break;
2497
1
        }
2498
480
        case DecodeContext::W_EXPR: {
2499
            // a: wrapper
2500
480
            if (in >= last) return {};
2501
480
            if (in[0].first == OP_FROMALTSTACK) {
2502
40
                ++in;
2503
40
                to_parse.emplace_back(DecodeContext::ALT, -1, -1);
2504
440
            } else {
2505
440
                to_parse.emplace_back(DecodeContext::SWAP, -1, -1);
2506
440
            }
2507
480
            to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2508
480
            break;
2509
480
        }
2510
1.45k
        case DecodeContext::MAYBE_AND_V: {
2511
            // If we reach a potential AND_V top-level, check if the next part of the script could be another AND_V child
2512
            // These op-codes cannot end any well-formed miniscript so cannot be used in an and_v node.
2513
1.45k
            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) {
2514
145
                to_parse.emplace_back(DecodeContext::AND_V, -1, -1);
2515
                // BKV_EXPR can contain more AND_V nodes
2516
145
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2517
145
            }
2518
1.45k
            break;
2519
480
        }
2520
440
        case DecodeContext::SWAP: {
2521
440
            if (in >= last || in[0].first != OP_SWAP || constructed.empty()) return {};
2522
440
            ++in;
2523
440
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S, Vector(std::move(constructed.back()))};
2524
440
            break;
2525
440
        }
2526
40
        case DecodeContext::ALT: {
2527
40
            if (in >= last || in[0].first != OP_TOALTSTACK || constructed.empty()) return {};
2528
40
            ++in;
2529
40
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A, Vector(std::move(constructed.back()))};
2530
40
            break;
2531
40
        }
2532
533
        case DecodeContext::CHECK: {
2533
533
            if (constructed.empty()) return {};
2534
533
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(std::move(constructed.back()))};
2535
533
            break;
2536
533
        }
2537
31
        case DecodeContext::DUP_IF: {
2538
31
            if (constructed.empty()) return {};
2539
31
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D, Vector(std::move(constructed.back()))};
2540
31
            break;
2541
31
        }
2542
176
        case DecodeContext::VERIFY: {
2543
176
            if (constructed.empty()) return {};
2544
176
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V, Vector(std::move(constructed.back()))};
2545
176
            break;
2546
176
        }
2547
0
        case DecodeContext::NON_ZERO: {
2548
0
            if (constructed.empty()) return {};
2549
0
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J, Vector(std::move(constructed.back()))};
2550
0
            break;
2551
0
        }
2552
274
        case DecodeContext::ZERO_NOTEQUAL: {
2553
274
            if (constructed.empty()) return {};
2554
274
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N, Vector(std::move(constructed.back()))};
2555
274
            break;
2556
274
        }
2557
145
        case DecodeContext::AND_V: {
2558
145
            if (constructed.size() < 2) return {};
2559
145
            BuildBack(ctx.MsContext(), Fragment::AND_V, constructed, /*reverse=*/true);
2560
145
            break;
2561
145
        }
2562
8
        case DecodeContext::AND_B: {
2563
8
            if (constructed.size() < 2) return {};
2564
8
            BuildBack(ctx.MsContext(), Fragment::AND_B, constructed, /*reverse=*/true);
2565
8
            break;
2566
8
        }
2567
0
        case DecodeContext::OR_B: {
2568
0
            if (constructed.size() < 2) return {};
2569
0
            BuildBack(ctx.MsContext(), Fragment::OR_B, constructed, /*reverse=*/true);
2570
0
            break;
2571
0
        }
2572
0
        case DecodeContext::OR_C: {
2573
0
            if (constructed.size() < 2) return {};
2574
0
            BuildBack(ctx.MsContext(), Fragment::OR_C, constructed, /*reverse=*/true);
2575
0
            break;
2576
0
        }
2577
4
        case DecodeContext::OR_D: {
2578
4
            if (constructed.size() < 2) return {};
2579
4
            BuildBack(ctx.MsContext(), Fragment::OR_D, constructed, /*reverse=*/true);
2580
4
            break;
2581
4
        }
2582
58
        case DecodeContext::ANDOR: {
2583
58
            if (constructed.size() < 3) return {};
2584
58
            Node left{std::move(constructed.back())};
2585
58
            constructed.pop_back();
2586
58
            Node right{std::move(constructed.back())};
2587
58
            constructed.pop_back();
2588
58
            Node mid{std::move(constructed.back())};
2589
58
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR, Vector(std::move(left), std::move(mid), std::move(right))};
2590
58
            break;
2591
58
        }
2592
577
        case DecodeContext::THRESH_W: {
2593
577
            if (in >= last) return {};
2594
577
            if (in[0].first == OP_ADD) {
2595
472
                ++in;
2596
472
                to_parse.emplace_back(DecodeContext::THRESH_W, n+1, k);
2597
472
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2598
472
            } else {
2599
105
                to_parse.emplace_back(DecodeContext::THRESH_E, n+1, k);
2600
                // All children of thresh have type modifier d, so cannot be and_v
2601
105
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2602
105
            }
2603
577
            break;
2604
577
        }
2605
105
        case DecodeContext::THRESH_E: {
2606
105
            if (k < 1 || k > n || constructed.size() < static_cast<size_t>(n)) return {};
2607
105
            std::vector<Node<Key>> subs;
2608
682
            for (int i = 0; i < n; ++i) {
2609
577
                Node sub{std::move(constructed.back())};
2610
577
                constructed.pop_back();
2611
577
                subs.push_back(std::move(sub));
2612
577
            }
2613
105
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs), k);
2614
105
            break;
2615
105
        }
2616
316
        case DecodeContext::ENDIF: {
2617
316
            if (in >= last) return {};
2618
2619
            // could be andor or or_i
2620
316
            if (in[0].first == OP_ELSE) {
2621
281
                ++in;
2622
281
                to_parse.emplace_back(DecodeContext::ENDIF_ELSE, -1, -1);
2623
281
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2624
281
            }
2625
            // could be j: or d: wrapper
2626
35
            else if (in[0].first == OP_IF) {
2627
31
                if (last - in >= 2 && in[1].first == OP_DUP) {
2628
31
                    in += 2;
2629
31
                    to_parse.emplace_back(DecodeContext::DUP_IF, -1, -1);
2630
31
                } else if (last - in >= 3 && in[1].first == OP_0NOTEQUAL && in[2].first == OP_SIZE) {
2631
0
                    in += 3;
2632
0
                    to_parse.emplace_back(DecodeContext::NON_ZERO, -1, -1);
2633
0
                }
2634
0
                else {
2635
0
                    return {};
2636
0
                }
2637
            // could be or_c or or_d
2638
31
            } else if (in[0].first == OP_NOTIF) {
2639
4
                ++in;
2640
4
                to_parse.emplace_back(DecodeContext::ENDIF_NOTIF, -1, -1);
2641
4
            }
2642
0
            else {
2643
0
                return {};
2644
0
            }
2645
316
            break;
2646
316
        }
2647
316
        case DecodeContext::ENDIF_NOTIF: {
2648
4
            if (in >= last) return {};
2649
4
            if (in[0].first == OP_IFDUP) {
2650
4
                ++in;
2651
4
                to_parse.emplace_back(DecodeContext::OR_D, -1, -1);
2652
4
            } else {
2653
0
                to_parse.emplace_back(DecodeContext::OR_C, -1, -1);
2654
0
            }
2655
            // or_c and or_d both require X to have type modifier d so, can't contain and_v
2656
4
            to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2657
4
            break;
2658
4
        }
2659
281
        case DecodeContext::ENDIF_ELSE: {
2660
281
            if (in >= last) return {};
2661
281
            if (in[0].first == OP_IF) {
2662
223
                ++in;
2663
223
                BuildBack(ctx.MsContext(), Fragment::OR_I, constructed, /*reverse=*/true);
2664
223
            } else if (in[0].first == OP_NOTIF) {
2665
58
                ++in;
2666
58
                to_parse.emplace_back(DecodeContext::ANDOR, -1, -1);
2667
                // andor requires X to have type modifier d, so it can't be and_v
2668
58
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2669
58
            } else {
2670
0
                return {};
2671
0
            }
2672
281
            break;
2673
281
        }
2674
9.00k
        }
2675
9.00k
    }
2676
234
    if (constructed.size() != 1) return {};
2677
234
    Node tl_node{std::move(constructed.front())};
2678
234
    tl_node.DuplicateKeyCheck(ctx);
2679
    // Note that due to how ComputeType works (only assign the type to the node if the
2680
    // subs' types are valid) this would fail if any node of tree is badly typed.
2681
234
    if (!tl_node.IsValidTopLevel()) return {};
2682
234
    return tl_node;
2683
234
}
2684
2685
} // namespace internal
2686
2687
template <typename Ctx>
2688
inline std::optional<Node<typename Ctx::Key>> FromString(const std::string& str, const Ctx& ctx)
2689
753
{
2690
753
    return internal::Parse<typename Ctx::Key>(str, ctx);
2691
753
}
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
2689
220
{
2690
220
    return internal::Parse<typename Ctx::Key>(str, ctx);
2691
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
2689
533
{
2690
533
    return internal::Parse<typename Ctx::Key>(str, ctx);
2691
533
}
2692
2693
template <typename Ctx>
2694
inline std::optional<Node<typename Ctx::Key>> FromScript(const CScript& script, const Ctx& ctx)
2695
4.14k
{
2696
4.14k
    using namespace internal;
2697
    // A too large Script is necessarily invalid, don't bother parsing it.
2698
4.14k
    if (script.size() > MaxScriptSize(ctx.MsContext())) return {};
2699
4.14k
    auto decomposed = DecomposeScript(script);
2700
4.14k
    if (!decomposed) return {};
2701
4.14k
    auto it = decomposed->begin();
2702
4.14k
    auto ret = DecodeScript<typename Ctx::Key>(it, decomposed->end(), ctx);
2703
4.14k
    if (!ret) return {};
2704
4.12k
    if (it != decomposed->end()) return {};
2705
4.12k
    return ret;
2706
4.12k
}
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
2695
132
{
2696
132
    using namespace internal;
2697
    // A too large Script is necessarily invalid, don't bother parsing it.
2698
132
    if (script.size() > MaxScriptSize(ctx.MsContext())) return {};
2699
132
    auto decomposed = DecomposeScript(script);
2700
132
    if (!decomposed) return {};
2701
128
    auto it = decomposed->begin();
2702
128
    auto ret = DecodeScript<typename Ctx::Key>(it, decomposed->end(), ctx);
2703
128
    if (!ret) return {};
2704
125
    if (it != decomposed->end()) return {};
2705
125
    return ret;
2706
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
2695
616
{
2696
616
    using namespace internal;
2697
    // A too large Script is necessarily invalid, don't bother parsing it.
2698
616
    if (script.size() > MaxScriptSize(ctx.MsContext())) return {};
2699
616
    auto decomposed = DecomposeScript(script);
2700
616
    if (!decomposed) return {};
2701
616
    auto it = decomposed->begin();
2702
616
    auto ret = DecodeScript<typename Ctx::Key>(it, decomposed->end(), ctx);
2703
616
    if (!ret) return {};
2704
603
    if (it != decomposed->end()) return {};
2705
603
    return ret;
2706
603
}
std::optional<miniscript::Node<TapSatisfier::Key>> miniscript::FromScript<TapSatisfier>(CScript const&, TapSatisfier const&)
Line
Count
Source
2695
3.16k
{
2696
3.16k
    using namespace internal;
2697
    // A too large Script is necessarily invalid, don't bother parsing it.
2698
3.16k
    if (script.size() > MaxScriptSize(ctx.MsContext())) return {};
2699
3.16k
    auto decomposed = DecomposeScript(script);
2700
3.16k
    if (!decomposed) return {};
2701
3.16k
    auto it = decomposed->begin();
2702
3.16k
    auto ret = DecodeScript<typename Ctx::Key>(it, decomposed->end(), ctx);
2703
3.16k
    if (!ret) return {};
2704
3.16k
    if (it != decomposed->end()) return {};
2705
3.16k
    return ret;
2706
3.16k
}
std::optional<miniscript::Node<WshSatisfier::Key>> miniscript::FromScript<WshSatisfier>(CScript const&, WshSatisfier const&)
Line
Count
Source
2695
237
{
2696
237
    using namespace internal;
2697
    // A too large Script is necessarily invalid, don't bother parsing it.
2698
237
    if (script.size() > MaxScriptSize(ctx.MsContext())) return {};
2699
237
    auto decomposed = DecomposeScript(script);
2700
237
    if (!decomposed) return {};
2701
237
    auto it = decomposed->begin();
2702
237
    auto ret = DecodeScript<typename Ctx::Key>(it, decomposed->end(), ctx);
2703
237
    if (!ret) return {};
2704
234
    if (it != decomposed->end()) return {};
2705
234
    return ret;
2706
234
}
2707
2708
} // namespace miniscript
2709
2710
#endif // BITCOIN_SCRIPT_MINISCRIPT_H