Coverage Report

Created: 2026-04-29 19:21

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 <algorithm>
9
#include <compare>
10
#include <concepts>
11
#include <cstdint>
12
#include <cstdlib>
13
#include <functional>
14
#include <iterator>
15
#include <memory>
16
#include <optional>
17
#include <set>
18
#include <stdexcept>
19
#include <tuple>
20
#include <utility>
21
#include <vector>
22
23
#include <consensus/consensus.h>
24
#include <policy/policy.h>
25
#include <script/interpreter.h>
26
#include <script/parsing.h>
27
#include <script/script.h>
28
#include <serialize.h>
29
#include <span.h>
30
#include <util/check.h>
31
#include <util/strencodings.h>
32
#include <util/string.h>
33
#include <util/vector.h>
34
35
namespace miniscript {
36
37
/** This type encapsulates the miniscript type system properties.
38
 *
39
 * Every miniscript expression is one of 4 basic types, and additionally has
40
 * a number of boolean type properties.
41
 *
42
 * The basic types are:
43
 * - "B" Base:
44
 *   - Takes its inputs from the top of the stack.
45
 *   - When satisfied, pushes a nonzero value of up to 4 bytes onto the stack.
46
 *   - When dissatisfied, pushes a 0 onto the stack.
47
 *   - This is used for most expressions, and required for the top level one.
48
 *   - For example: older(n) = <n> OP_CHECKSEQUENCEVERIFY.
49
 * - "V" Verify:
50
 *   - Takes its inputs from the top of the stack.
51
 *   - When satisfied, pushes nothing.
52
 *   - Cannot be dissatisfied.
53
 *   - This can be obtained by adding an OP_VERIFY to a B, modifying the last opcode
54
 *     of a B to its -VERIFY version (only for OP_CHECKSIG, OP_CHECKSIGVERIFY,
55
 *     OP_NUMEQUAL and OP_EQUAL), or by combining a V fragment under some conditions.
56
 *   - For example vc:pk_k(key) = <key> OP_CHECKSIGVERIFY
57
 * - "K" Key:
58
 *   - Takes its inputs from the top of the stack.
59
 *   - Becomes a B when followed by OP_CHECKSIG.
60
 *   - Always pushes a public key onto the stack, for which a signature is to be
61
 *     provided to satisfy the expression.
62
 *   - For example pk_h(key) = OP_DUP OP_HASH160 <Hash160(key)> OP_EQUALVERIFY
63
 * - "W" Wrapped:
64
 *   - Takes its input from one below the top of the stack.
65
 *   - When satisfied, pushes a nonzero value (like B) on top of the stack, or one below.
66
 *   - When dissatisfied, pushes 0 op top of the stack or one below.
67
 *   - Is always "OP_SWAP [B]" or "OP_TOALTSTACK [B] OP_FROMALTSTACK".
68
 *   - For example sc:pk_k(key) = OP_SWAP <key> OP_CHECKSIG
69
 *
70
 * There are type properties that help reasoning about correctness:
71
 * - "z" Zero-arg:
72
 *   - Is known to always consume exactly 0 stack elements.
73
 *   - For example after(n) = <n> OP_CHECKLOCKTIMEVERIFY
74
 * - "o" One-arg:
75
 *   - Is known to always consume exactly 1 stack element.
76
 *   - Conflicts with property 'z'
77
 *   - For example sha256(hash) = OP_SIZE 32 OP_EQUALVERIFY OP_SHA256 <hash> OP_EQUAL
78
 * - "n" Nonzero:
79
 *   - For every way this expression can be satisfied, a satisfaction exists that never needs
80
 *     a zero top stack element.
81
 *   - Conflicts with property 'z' and with type 'W'.
82
 * - "d" Dissatisfiable:
83
 *   - There is an easy way to construct a dissatisfaction for this expression.
84
 *   - Conflicts with type 'V'.
85
 * - "u" Unit:
86
 *   - In case of satisfaction, an exact 1 is put on the stack (rather than just nonzero).
87
 *   - Conflicts with type 'V'.
88
 *
89
 * Additional type properties help reasoning about nonmalleability:
90
 * - "e" Expression:
91
 *   - This implies property 'd', but the dissatisfaction is nonmalleable.
92
 *   - This generally requires 'e' for all subexpressions which are invoked for that
93
 *     dissatisfaction, and property 'f' for the unexecuted subexpressions in that case.
94
 *   - Conflicts with type 'V'.
95
 * - "f" Forced:
96
 *   - Dissatisfactions (if any) for this expression always involve at least one signature.
97
 *   - Is always true for type 'V'.
98
 * - "s" Safe:
99
 *   - Satisfactions for this expression always involve at least one signature.
100
 * - "m" Nonmalleable:
101
 *   - For every way this expression can be satisfied (which may be none),
102
 *     a nonmalleable satisfaction exists.
103
 *   - This generally requires 'm' for all subexpressions, and 'e' for all subexpressions
104
 *     which are dissatisfied when satisfying the parent.
105
 *
106
 * One type property is an implementation detail:
107
 * - "x" Expensive verify:
108
 *   - Expressions with this property have a script whose last opcode is not EQUAL, CHECKSIG, or CHECKMULTISIG.
109
 *   - Not having this property means that it can be converted to a V at no cost (by switching to the
110
 *     -VERIFY version of the last opcode).
111
 *
112
 * Five more type properties for representing timelock information. Spend paths
113
 * in miniscripts containing conflicting timelocks and heightlocks cannot be spent together.
114
 * This helps users detect if miniscript does not match the semantic behaviour the
115
 * user expects.
116
 * - "g" Whether the branch contains a relative time timelock
117
 * - "h" Whether the branch contains a relative height timelock
118
 * - "i" Whether the branch contains an absolute time timelock
119
 * - "j" Whether the branch contains an absolute height timelock
120
 * - "k"
121
 *   - Whether all satisfactions of this expression don't contain a mix of heightlock and timelock
122
 *     of the same type.
123
 *   - If the miniscript does not have the "k" property, the miniscript template will not match
124
 *     the user expectation of the corresponding spending policy.
125
 * For each of these properties the subset rule holds: an expression with properties X, Y, and Z, is also
126
 * valid in places where an X, a Y, a Z, an XY, ... is expected.
127
*/
128
class Type {
129
    //! Internal bitmap of properties (see ""_mst operator for details).
130
    uint32_t m_flags;
131
132
    //! Internal constructor used by the ""_mst operator.
133
28.4M
    explicit constexpr Type(uint32_t flags) : m_flags(flags) {}
134
135
public:
136
    //! The only way to publicly construct a Type is using this literal operator.
137
    friend consteval Type operator""_mst(const char* c, size_t l);
138
139
    //! Compute the type with the union of properties.
140
14.1M
    constexpr Type operator|(Type x) const { return Type(m_flags | x.m_flags); }
141
142
    //! Compute the type with the intersection of properties.
143
14.1M
    constexpr Type operator&(Type x) const { return Type(m_flags & x.m_flags); }
144
145
    //! Check whether the left hand's properties are superset of the right's (= left is a subtype of right).
146
257M
    constexpr bool operator<<(Type x) const { return (x.m_flags & ~m_flags) == 0; }
147
148
    //! Comparison operator to enable use in sets/maps (total ordering incompatible with <<).
149
0
    constexpr bool operator<(Type x) const { return m_flags < x.m_flags; }
150
151
    //! Equality operator.
152
5.99M
    constexpr bool operator==(Type x) const { return m_flags == x.m_flags; }
153
154
    //! The empty type if x is false, itself otherwise.
155
92.7k
    constexpr Type If(bool x) const { return Type(x ? m_flags : 0); }
156
};
157
158
//! Literal operator to construct Type objects.
159
inline consteval Type operator""_mst(const char* c, size_t l)
160
{
161
    Type typ{0};
162
163
    for (const char *p = c; p < c + l; p++) {
164
        typ = typ | Type(
165
            *p == 'B' ? 1 << 0 : // Base type
166
            *p == 'V' ? 1 << 1 : // Verify type
167
            *p == 'K' ? 1 << 2 : // Key type
168
            *p == 'W' ? 1 << 3 : // Wrapped type
169
            *p == 'z' ? 1 << 4 : // Zero-arg property
170
            *p == 'o' ? 1 << 5 : // One-arg property
171
            *p == 'n' ? 1 << 6 : // Nonzero arg property
172
            *p == 'd' ? 1 << 7 : // Dissatisfiable property
173
            *p == 'u' ? 1 << 8 : // Unit property
174
            *p == 'e' ? 1 << 9 : // Expression property
175
            *p == 'f' ? 1 << 10 : // Forced property
176
            *p == 's' ? 1 << 11 : // Safe property
177
            *p == 'm' ? 1 << 12 : // Nonmalleable property
178
            *p == 'x' ? 1 << 13 : // Expensive verify
179
            *p == 'g' ? 1 << 14 : // older: contains relative time timelock   (csv_time)
180
            *p == 'h' ? 1 << 15 : // older: contains relative height timelock (csv_height)
181
            *p == 'i' ? 1 << 16 : // after: contains time timelock   (cltv_time)
182
            *p == 'j' ? 1 << 17 : // after: contains height timelock   (cltv_height)
183
            *p == 'k' ? 1 << 18 : // does not contain a combination of height and time locks
184
            (throw std::logic_error("Unknown character in _mst literal"), 0)
185
        );
186
    }
187
188
    return typ;
189
}
190
191
using Opcode = std::pair<opcodetype, std::vector<unsigned char>>;
192
193
template<typename Key> class Node;
194
195
//! Unordered traversal of a miniscript node tree.
196
template <typename Key, std::invocable<const Node<Key>&> Fn>
197
void ForEachNode(const Node<Key>& root, Fn&& fn)
198
800
{
199
800
    std::vector<std::reference_wrapper<const Node<Key>>> stack{root};
200
996k
    while (!stack.empty()) {
201
995k
        const Node<Key>& node = stack.back();
202
995k
        std::invoke(fn, node);
203
995k
        stack.pop_back();
204
995k
        for (const auto& sub : node.Subs()) {
205
995k
            stack.emplace_back(sub);
206
995k
        }
207
995k
    }
208
800
}
209
210
//! The different node types in miniscript.
211
enum class Fragment {
212
    JUST_0,    //!< OP_0
213
    JUST_1,    //!< OP_1
214
    PK_K,      //!< [key]
215
    PK_H,      //!< OP_DUP OP_HASH160 [keyhash] OP_EQUALVERIFY
216
    OLDER,     //!< [n] OP_CHECKSEQUENCEVERIFY
217
    AFTER,     //!< [n] OP_CHECKLOCKTIMEVERIFY
218
    SHA256,    //!< OP_SIZE 32 OP_EQUALVERIFY OP_SHA256 [hash] OP_EQUAL
219
    HASH256,   //!< OP_SIZE 32 OP_EQUALVERIFY OP_HASH256 [hash] OP_EQUAL
220
    RIPEMD160, //!< OP_SIZE 32 OP_EQUALVERIFY OP_RIPEMD160 [hash] OP_EQUAL
221
    HASH160,   //!< OP_SIZE 32 OP_EQUALVERIFY OP_HASH160 [hash] OP_EQUAL
222
    WRAP_A,    //!< OP_TOALTSTACK [X] OP_FROMALTSTACK
223
    WRAP_S,    //!< OP_SWAP [X]
224
    WRAP_C,    //!< [X] OP_CHECKSIG
225
    WRAP_D,    //!< OP_DUP OP_IF [X] OP_ENDIF
226
    WRAP_V,    //!< [X] OP_VERIFY (or -VERIFY version of last opcode in X)
227
    WRAP_J,    //!< OP_SIZE OP_0NOTEQUAL OP_IF [X] OP_ENDIF
228
    WRAP_N,    //!< [X] OP_0NOTEQUAL
229
    AND_V,     //!< [X] [Y]
230
    AND_B,     //!< [X] [Y] OP_BOOLAND
231
    OR_B,      //!< [X] [Y] OP_BOOLOR
232
    OR_C,      //!< [X] OP_NOTIF [Y] OP_ENDIF
233
    OR_D,      //!< [X] OP_IFDUP OP_NOTIF [Y] OP_ENDIF
234
    OR_I,      //!< OP_IF [X] OP_ELSE [Y] OP_ENDIF
235
    ANDOR,     //!< [X] OP_NOTIF [Z] OP_ELSE [Y] OP_ENDIF
236
    THRESH,    //!< [X1] ([Xn] OP_ADD)* [k] OP_EQUAL
237
    MULTI,     //!< [k] [key_n]* [n] OP_CHECKMULTISIG (only available within P2WSH context)
238
    MULTI_A,   //!< [key_0] OP_CHECKSIG ([key_n] OP_CHECKSIGADD)* [k] OP_NUMEQUAL (only within Tapscript ctx)
239
    // AND_N(X,Y) is represented as ANDOR(X,Y,0)
240
    // WRAP_T(X) is represented as AND_V(X,1)
241
    // WRAP_L(X) is represented as OR_I(0,X)
242
    // WRAP_U(X) is represented as OR_I(X,0)
243
};
244
245
enum class Availability {
246
    NO,
247
    YES,
248
    MAYBE,
249
};
250
251
enum class MiniscriptContext {
252
    P2WSH,
253
    TAPSCRIPT,
254
};
255
256
/** Whether the context Tapscript, ensuring the only other possibility is P2WSH. */
257
constexpr bool IsTapscript(MiniscriptContext ms_ctx)
258
20.2M
{
259
20.2M
    switch (ms_ctx) {
260
66.0k
        case MiniscriptContext::P2WSH: return false;
261
20.2M
        case MiniscriptContext::TAPSCRIPT: return true;
262
20.2M
    }
263
20.2M
    assert(false);
264
0
}
265
266
namespace internal {
267
268
//! The maximum size of a witness item for a Miniscript under Tapscript context. (A BIP340 signature with a sighash type byte.)
269
static constexpr uint32_t MAX_TAPMINISCRIPT_STACK_ELEM_SIZE{65};
270
271
//! version + nLockTime
272
constexpr uint32_t TX_OVERHEAD{4 + 4};
273
//! prevout + nSequence + scriptSig
274
constexpr uint32_t TXIN_BYTES_NO_WITNESS{36 + 4 + 1};
275
//! nValue + script len + OP_0 + pushdata 32.
276
constexpr uint32_t P2WSH_TXOUT_BYTES{8 + 1 + 1 + 33};
277
//! Data other than the witness in a transaction. Overhead + vin count + one vin + vout count + one vout + segwit marker
278
constexpr uint32_t TX_BODY_LEEWAY_WEIGHT{(TX_OVERHEAD + GetSizeOfCompactSize(1) + TXIN_BYTES_NO_WITNESS + GetSizeOfCompactSize(1) + P2WSH_TXOUT_BYTES) * WITNESS_SCALE_FACTOR + 2};
279
//! Maximum possible stack size to spend a Taproot output (excluding the script itself).
280
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};
281
/** The maximum size of a script depending on the context. */
282
constexpr uint32_t MaxScriptSize(MiniscriptContext ms_ctx)
283
5.99M
{
284
5.99M
    if (IsTapscript(ms_ctx)) {
285
        // Leaf scripts under Tapscript are not explicitly limited in size. They are only implicitly
286
        // bounded by the maximum standard size of a spending transaction. Let the maximum script
287
        // size conservatively be small enough such that even a maximum sized witness and a reasonably
288
        // sized spending transaction can spend an output paying to this script without running into
289
        // the maximum standard tx size limit.
290
5.96M
        constexpr auto max_size{MAX_STANDARD_TX_WEIGHT - TX_BODY_LEEWAY_WEIGHT - MAX_TAPSCRIPT_SAT_SIZE};
291
5.96M
        return max_size - GetSizeOfCompactSize(max_size);
292
5.96M
    }
293
23.6k
    return MAX_STANDARD_P2WSH_SCRIPT_SIZE;
294
5.99M
}
295
296
//! Helper function for Node::CalcType.
297
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);
298
299
//! Helper function for Node::CalcScriptLen.
300
size_t ComputeScriptLen(Fragment fragment, Type sub0typ, size_t subsize, uint32_t k, size_t n_subs, size_t n_keys, MiniscriptContext ms_ctx);
301
302
//! A helper sanitizer/checker for the output of CalcType.
303
Type SanitizeType(Type x);
304
305
//! An object representing a sequence of witness stack elements.
306
struct InputStack {
307
    /** Whether this stack is valid for its intended purpose (satisfaction or dissatisfaction of a Node).
308
     *  The MAYBE value is used for size estimation, when keys/preimages may actually be unavailable,
309
     *  but may be available at signing time. This makes the InputStack structure and signing logic,
310
     *  filled with dummy signatures/preimages usable for witness size estimation.
311
     */
312
    Availability available = Availability::YES;
313
    //! Whether this stack contains a digital signature.
314
    bool has_sig = false;
315
    //! Whether this stack is malleable (can be turned into an equally valid other stack by a third party).
316
    bool malleable = false;
317
    //! Whether this stack is non-canonical (using a construction known to be unnecessary for satisfaction).
318
    //! Note that this flag does not affect the satisfaction algorithm; it is only used for sanity checking.
319
    bool non_canon = false;
320
    //! Serialized witness size.
321
    size_t size = 0;
322
    //! Data elements.
323
    std::vector<std::vector<unsigned char>> stack;
324
    //! Construct an empty stack (valid).
325
4.43k
    InputStack() = default;
326
    //! Construct a valid single-element stack (with an element up to 75 bytes).
327
489k
    InputStack(std::vector<unsigned char> in) : size(in.size() + 1), stack(Vector(std::move(in))) {}
328
    //! Change availability
329
    InputStack& SetAvailable(Availability avail);
330
    //! Mark this input stack as having a signature.
331
    InputStack& SetWithSig();
332
    //! Mark this input stack as non-canonical (known to not be necessary in non-malleable satisfactions).
333
    InputStack& SetNonCanon();
334
    //! Mark this input stack as malleable.
335
    InputStack& SetMalleable(bool x = true);
336
    //! Concatenate two input stacks.
337
    friend InputStack operator+(InputStack a, InputStack b);
338
    //! Choose between two potential input stacks.
339
    friend InputStack operator|(InputStack a, InputStack b);
340
};
341
342
/** A stack consisting of a single zero-length element (interpreted as 0 by the script interpreter in numeric context). */
343
static const auto ZERO = InputStack(std::vector<unsigned char>());
344
/** A stack consisting of a single malleable 32-byte 0x0000...0000 element (for dissatisfying hash challenges). */
345
static const auto ZERO32 = InputStack(std::vector<unsigned char>(32, 0)).SetMalleable();
346
/** A stack consisting of a single 0x01 element (interpreted as 1 by the script interpreted in numeric context). */
347
static const auto ONE = InputStack(Vector((unsigned char)1));
348
/** The empty stack. */
349
static const auto EMPTY = InputStack();
350
/** A stack representing the lack of any (dis)satisfactions. */
351
static const auto INVALID = InputStack().SetAvailable(Availability::NO);
352
353
//! A pair of a satisfaction and a dissatisfaction InputStack.
354
struct InputResult {
355
    InputStack nsat, sat;
356
357
    template<typename A, typename B>
358
838k
    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
358
378k
    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
358
940
    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
358
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
358
41.6k
    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
358
2.10k
    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
358
2.45k
    InputResult(A&& in_nsat, B&& in_sat) : nsat(std::forward<A>(in_nsat)), sat(std::forward<B>(in_sat)) {}
359
};
360
361
//! Class whose objects represent the maximum of a list of integers.
362
template <typename I>
363
class MaxInt
364
{
365
    bool valid;
366
    I value;
367
368
public:
369
41.6k
    MaxInt() : valid(false), value(0) {}
370
103k
    MaxInt(I val) : valid(true), value(val) {}
371
372
2.70k
    bool Valid() const { return valid; }
373
2.69k
    I Value() const { return value; }
374
375
56.7k
    friend MaxInt<I> operator+(const MaxInt<I>& a, const MaxInt<I>& b) {
376
56.7k
        if (!a.valid || !b.valid) return {};
377
42.0k
        return a.value + b.value;
378
56.7k
    }
379
380
9.77k
    friend MaxInt<I> operator|(const MaxInt<I>& a, const MaxInt<I>& b) {
381
9.77k
        if (!a.valid) return b;
382
8.53k
        if (!b.valid) return a;
383
7.21k
        return std::max(a.value, b.value);
384
8.53k
    }
385
};
386
387
struct Ops {
388
    //! Non-push opcodes.
389
    uint32_t count;
390
    //! Number of keys in possibly executed OP_CHECKMULTISIG(VERIFY)s to satisfy.
391
    MaxInt<uint32_t> sat;
392
    //! Number of keys in possibly executed OP_CHECKMULTISIG(VERIFY)s to dissatisfy.
393
    MaxInt<uint32_t> dsat;
394
395
7.03M
    Ops(uint32_t in_count, MaxInt<uint32_t> in_sat, MaxInt<uint32_t> in_dsat) : count(in_count), sat(in_sat), dsat(in_dsat) {};
396
};
397
398
/** A data structure to help the calculation of stack size limits.
399
 *
400
 * Conceptually, every SatInfo object corresponds to a (possibly empty) set of script execution
401
 * traces (sequences of opcodes).
402
 * - SatInfo{} corresponds to the empty set.
403
 * - SatInfo{n, e} corresponds to a single trace whose net effect is removing n elements from the
404
 *   stack (may be negative for a net increase), and reaches a maximum of e stack elements more
405
 *   than it ends with.
406
 * - operator| is the union operation: (a | b) corresponds to the union of the traces in a and the
407
 *   traces in b.
408
 * - operator+ is the concatenation operator: (a + b) corresponds to the set of traces formed by
409
 *   concatenating any trace in a with any trace in b.
410
 *
411
 * Its fields are:
412
 * - valid is true if the set is non-empty.
413
 * - netdiff (if valid) is the largest difference between stack size at the beginning and at the
414
 *   end of the script across all traces in the set.
415
 * - exec (if valid) is the largest difference between stack size anywhere during execution and at
416
 *   the end of the script, across all traces in the set (note that this is not necessarily due
417
 *   to the same trace as the one that resulted in the value for netdiff).
418
 *
419
 * This allows us to build up stack size limits for any script efficiently, by starting from the
420
 * individual opcodes miniscripts correspond to, using concatenation to construct scripts, and
421
 * using the union operation to choose between execution branches. Since any top-level script
422
 * satisfaction ends with a single stack element, we know that for a full script:
423
 * - netdiff+1 is the maximal initial stack size (relevant for P2WSH stack limits).
424
 * - exec+1 is the maximal stack size reached during execution (relevant for P2TR stack limits).
425
 *
426
 * Mathematically, SatInfo forms a semiring:
427
 * - operator| is the semiring addition operator, with identity SatInfo{}, and which is commutative
428
 *   and associative.
429
 * - operator+ is the semiring multiplication operator, with identity SatInfo{0}, and which is
430
 *   associative.
431
 * - operator+ is distributive over operator|, so (a + (b | c)) = (a+b | a+c). This means we do not
432
 *   need to actually materialize all possible full execution traces over the whole script (which
433
 *   may be exponential in the length of the script); instead we can use the union operation at the
434
 *   individual subexpression level, and concatenate the result with subexpressions before and
435
 *   after it.
436
 * - It is not a commutative semiring, because a+b can differ from b+a. For example, "OP_1 OP_DROP"
437
 *   has exec=1, while "OP_DROP OP_1" has exec=0.
438
 */
439
class SatInfo
440
{
441
    //! Whether a canonical satisfaction/dissatisfaction is possible at all.
442
    bool valid;
443
    //! How much higher the stack size at start of execution can be compared to at the end.
444
    int32_t netdiff;
445
    //! How much higher the stack size can be during execution compared to at the end.
446
    int32_t exec;
447
448
public:
449
    /** Empty script set. */
450
26.2k
    constexpr SatInfo() noexcept : valid(false), netdiff(0), exec(0) {}
451
452
    /** Script set with a single script in it, with specified netdiff and exec. */
453
    constexpr SatInfo(int32_t in_netdiff, int32_t in_exec) noexcept :
454
136k
        valid{true}, netdiff{in_netdiff}, exec{in_exec} {}
455
456
7.18k
    bool Valid() const { return valid; }
457
2.73k
    int32_t NetDiff() const { return netdiff; }
458
4.42k
    int32_t Exec() const { return exec; }
459
460
    /** Script set union. */
461
    constexpr friend SatInfo operator|(const SatInfo& a, const SatInfo& b) noexcept
462
4.88k
    {
463
        // Union with an empty set is itself.
464
4.88k
        if (!a.valid) return b;
465
4.27k
        if (!b.valid) return a;
466
        // Otherwise the netdiff and exec of the union is the maximum of the individual values.
467
3.60k
        return {std::max(a.netdiff, b.netdiff), std::max(a.exec, b.exec)};
468
4.27k
    }
469
470
    /** Script set concatenation. */
471
    constexpr friend SatInfo operator+(const SatInfo& a, const SatInfo& b) noexcept
472
79.1k
    {
473
        // Concatenation with an empty set yields an empty set.
474
79.1k
        if (!a.valid || !b.valid) return {};
475
        // Otherwise, the maximum stack size difference for the combined scripts is the sum of the
476
        // netdiffs, and the maximum stack size difference anywhere is either b.exec (if the
477
        // maximum occurred in b) or b.netdiff+a.exec (if the maximum occurred in a).
478
66.3k
        return {a.netdiff + b.netdiff, std::max(b.exec, b.netdiff + a.exec)};
479
79.1k
    }
480
481
    /** The empty script. */
482
808
    static constexpr SatInfo Empty() noexcept { return {0, 0}; }
483
    /** A script consisting of a single push opcode. */
484
17.7k
    static constexpr SatInfo Push() noexcept { return {-1, 0}; }
485
    /** A script consisting of a single hash opcode. */
486
1.17k
    static constexpr SatInfo Hash() noexcept { return {0, 0}; }
487
    /** A script consisting of just a repurposed nop (OP_CHECKLOCKTIMEVERIFY, OP_CHECKSEQUENCEVERIFY). */
488
9.05k
    static constexpr SatInfo Nop() noexcept { return {0, 0}; }
489
    /** A script consisting of just OP_IF or OP_NOTIF. Note that OP_ELSE and OP_ENDIF have no stack effect. */
490
2.82k
    static constexpr SatInfo If() noexcept { return {1, 1}; }
491
    /** A script consisting of just a binary operator (OP_BOOLAND, OP_BOOLOR, OP_ADD). */
492
15.6k
    static constexpr SatInfo BinaryOp() noexcept { return {1, 1}; }
493
494
    // Scripts for specific individual opcodes.
495
1.00k
    static constexpr SatInfo OP_DUP() noexcept { return {-1, 0}; }
496
396
    static constexpr SatInfo OP_IFDUP(bool nonzero) noexcept { return {nonzero ? -1 : 0, 0}; }
497
1.17k
    static constexpr SatInfo OP_EQUALVERIFY() noexcept { return {2, 2}; }
498
1.20k
    static constexpr SatInfo OP_EQUAL() noexcept { return {1, 1}; }
499
427
    static constexpr SatInfo OP_SIZE() noexcept { return {-1, 0}; }
500
12.1k
    static constexpr SatInfo OP_CHECKSIG() noexcept { return {1, 1}; }
501
32
    static constexpr SatInfo OP_0NOTEQUAL() noexcept { return {0, 0}; }
502
1.60k
    static constexpr SatInfo OP_VERIFY() noexcept { return {1, 1}; }
503
};
504
505
class StackSize
506
{
507
    SatInfo sat, dsat;
508
509
public:
510
28.3k
    constexpr StackSize(SatInfo in_sat, SatInfo in_dsat) noexcept : sat(in_sat), dsat(in_dsat) {};
511
7.11k
    constexpr StackSize(SatInfo in_both) noexcept : sat(in_both), dsat(in_both) {};
512
513
46.6k
    const SatInfo& Sat() const { return sat; }
514
27.8k
    const SatInfo& Dsat() const { return dsat; }
515
};
516
517
struct WitnessSize {
518
    //! Maximum witness size to satisfy;
519
    MaxInt<uint32_t> sat;
520
    //! Maximum witness size to dissatisfy;
521
    MaxInt<uint32_t> dsat;
522
523
29.4k
    WitnessSize(MaxInt<uint32_t> in_sat, MaxInt<uint32_t> in_dsat) : sat(in_sat), dsat(in_dsat) {};
524
};
525
526
struct NoDupCheck {};
527
528
} // namespace internal
529
530
//! A node in a miniscript expression.
531
template <typename Key>
532
class Node
533
{
534
    //! What node type this node is.
535
    enum Fragment fragment;
536
    //! The k parameter (time for OLDER/AFTER, threshold for THRESH(_M))
537
    uint32_t k = 0;
538
    //! The keys used by this expression (only for PK_K/PK_H/MULTI)
539
    std::vector<Key> keys;
540
    //! The data bytes in this expression (only for HASH160/HASH256/SHA256/RIPEMD160).
541
    std::vector<unsigned char> data;
542
    //! Subexpressions (for WRAP_*/AND_*/OR_*/ANDOR/THRESH)
543
    std::vector<Node> subs;
544
    //! The Script context for this node. Either P2WSH or Tapscript.
545
    MiniscriptContext m_script_ctx;
546
547
public:
548
    // Permit 1 level deep recursion since we own instances of our own type.
549
    // NOLINTBEGIN(misc-no-recursion)
550
    ~Node()
551
15.1M
    {
552
        // Destroy the subexpressions iteratively after moving out their
553
        // subexpressions to avoid a stack-overflow due to recursive calls to
554
        // the subs' destructors.
555
        // We move vectors in order to only update array-pointers inside them
556
        // rather than moving individual Node instances which would involve
557
        // moving/copying each Node field.
558
15.1M
        std::vector<std::vector<Node>> queue;
559
15.1M
        queue.push_back(std::move(subs));
560
22.1M
        do {
561
22.1M
            auto flattening{std::move(queue.back())};
562
22.1M
            queue.pop_back();
563
22.1M
            for (Node& n : flattening) {
564
7.02M
                if (!n.subs.empty()) queue.push_back(std::move(n.subs));
565
7.02M
            }
566
22.1M
        } while (!queue.empty());
567
15.1M
    }
miniscript::Node<CPubKey>::~Node()
Line
Count
Source
551
73.1k
    {
552
        // Destroy the subexpressions iteratively after moving out their
553
        // subexpressions to avoid a stack-overflow due to recursive calls to
554
        // the subs' destructors.
555
        // We move vectors in order to only update array-pointers inside them
556
        // rather than moving individual Node instances which would involve
557
        // moving/copying each Node field.
558
73.1k
        std::vector<std::vector<Node>> queue;
559
73.1k
        queue.push_back(std::move(subs));
560
90.0k
        do {
561
90.0k
            auto flattening{std::move(queue.back())};
562
90.0k
            queue.pop_back();
563
90.0k
            for (Node& n : flattening) {
564
26.0k
                if (!n.subs.empty()) queue.push_back(std::move(n.subs));
565
26.0k
            }
566
90.0k
        } while (!queue.empty());
567
73.1k
    }
miniscript::Node<unsigned int>::~Node()
Line
Count
Source
551
4.52M
    {
552
        // Destroy the subexpressions iteratively after moving out their
553
        // subexpressions to avoid a stack-overflow due to recursive calls to
554
        // the subs' destructors.
555
        // We move vectors in order to only update array-pointers inside them
556
        // rather than moving individual Node instances which would involve
557
        // moving/copying each Node field.
558
4.52M
        std::vector<std::vector<Node>> queue;
559
4.52M
        queue.push_back(std::move(subs));
560
6.24M
        do {
561
6.24M
            auto flattening{std::move(queue.back())};
562
6.24M
            queue.pop_back();
563
6.24M
            for (Node& n : flattening) {
564
1.72M
                if (!n.subs.empty()) queue.push_back(std::move(n.subs));
565
1.72M
            }
566
6.24M
        } while (!queue.empty());
567
4.52M
    }
miniscript::Node<XOnlyPubKey>::~Node()
Line
Count
Source
551
10.5M
    {
552
        // Destroy the subexpressions iteratively after moving out their
553
        // subexpressions to avoid a stack-overflow due to recursive calls to
554
        // the subs' destructors.
555
        // We move vectors in order to only update array-pointers inside them
556
        // rather than moving individual Node instances which would involve
557
        // moving/copying each Node field.
558
10.5M
        std::vector<std::vector<Node>> queue;
559
10.5M
        queue.push_back(std::move(subs));
560
15.8M
        do {
561
15.8M
            auto flattening{std::move(queue.back())};
562
15.8M
            queue.pop_back();
563
15.8M
            for (Node& n : flattening) {
564
5.27M
                if (!n.subs.empty()) queue.push_back(std::move(n.subs));
565
5.27M
            }
566
15.8M
        } while (!queue.empty());
567
10.5M
    }
568
    // NOLINTEND(misc-no-recursion)
569
570
    Node<Key> Clone() const
571
190
    {
572
        // Use TreeEval() to avoid a stack-overflow due to recursion
573
531k
        auto upfn = [](const Node& node, std::span<Node> children) {
574
531k
            std::vector<Node> new_subs;
575
531k
            for (auto& child : children) {
576
                // It's fine to move from children as they are new nodes having
577
                // been produced by calling this function one level down.
578
530k
                new_subs.push_back(std::move(child));
579
530k
            }
580
531k
            return Node{internal::NoDupCheck{}, node.m_script_ctx, node.fragment, std::move(new_subs), node.keys, node.data, node.k};
581
531k
        };
582
190
        return TreeEval<Node>(upfn);
583
190
    }
584
585
1.00M
    enum Fragment Fragment() const { return fragment; }
miniscript::Node<CPubKey>::Fragment() const
Line
Count
Source
585
8.47k
    enum Fragment Fragment() const { return fragment; }
miniscript::Node<unsigned int>::Fragment() const
Line
Count
Source
585
995k
    enum Fragment Fragment() const { return fragment; }
586
2.35k
    uint32_t K() const { return k; }
miniscript::Node<CPubKey>::K() const
Line
Count
Source
586
2.10k
    uint32_t K() const { return k; }
miniscript::Node<unsigned int>::K() const
Line
Count
Source
586
253
    uint32_t K() const { return k; }
587
8.47k
    const std::vector<Key>& Keys() const { return keys; }
588
48
    const std::vector<unsigned char>& Data() const { return data; }
589
2.20M
    const std::vector<Node>& Subs() const { return subs; }
miniscript::Node<CPubKey>::Subs() const
Line
Count
Source
589
8.47k
    const std::vector<Node>& Subs() const { return subs; }
miniscript::Node<unsigned int>::Subs() const
Line
Count
Source
589
2.19M
    const std::vector<Node>& Subs() const { return subs; }
590
591
private:
592
    //! Cached ops counts.
593
    internal::Ops ops;
594
    //! Cached stack size bounds.
595
    internal::StackSize ss;
596
    //! Cached witness size bounds.
597
    internal::WitnessSize ws;
598
    //! Cached expression type (computed by CalcType and fed through SanitizeType).
599
    Type typ;
600
    //! Cached script length (computed by CalcScriptLen).
601
    size_t scriptlen;
602
    //! Whether a public key appears more than once in this node. This value is initialized
603
    //! by all constructors except the NoDupCheck ones. The NoDupCheck ones skip the
604
    //! computation, requiring it to be done manually by invoking DuplicateKeyCheck().
605
    //! DuplicateKeyCheck(), or a non-NoDupCheck constructor, will compute has_duplicate_keys
606
    //! for all subnodes as well.
607
    mutable std::optional<bool> has_duplicate_keys;
608
609
    // Constructor which takes all of the data that a Node could possibly contain.
610
    // This is kept private as no valid fragment has all of these arguments.
611
    // Only used by Clone()
612
    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)
613
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()) {}
614
615
    //! Compute the length of the script for this miniscript (including children).
616
    size_t CalcScriptLen() const
617
7.03M
    {
618
7.03M
        size_t subsize = 0;
619
7.03M
        for (const auto& sub : subs) {
620
7.02M
            subsize += sub.ScriptSize();
621
7.02M
        }
622
7.03M
        Type sub0type = subs.size() > 0 ? subs[0].GetType() : ""_mst;
623
7.03M
        return internal::ComputeScriptLen(fragment, sub0type, subsize, k, subs.size(), keys.size(), m_script_ctx);
624
7.03M
    }
miniscript::Node<CPubKey>::CalcScriptLen() const
Line
Count
Source
617
28.2k
    {
618
28.2k
        size_t subsize = 0;
619
28.2k
        for (const auto& sub : subs) {
620
26.0k
            subsize += sub.ScriptSize();
621
26.0k
        }
622
28.2k
        Type sub0type = subs.size() > 0 ? subs[0].GetType() : ""_mst;
623
28.2k
        return internal::ComputeScriptLen(fragment, sub0type, subsize, k, subs.size(), keys.size(), m_script_ctx);
624
28.2k
    }
miniscript::Node<unsigned int>::CalcScriptLen() const
Line
Count
Source
617
1.72M
    {
618
1.72M
        size_t subsize = 0;
619
1.72M
        for (const auto& sub : subs) {
620
1.72M
            subsize += sub.ScriptSize();
621
1.72M
        }
622
1.72M
        Type sub0type = subs.size() > 0 ? subs[0].GetType() : ""_mst;
623
1.72M
        return internal::ComputeScriptLen(fragment, sub0type, subsize, k, subs.size(), keys.size(), m_script_ctx);
624
1.72M
    }
miniscript::Node<XOnlyPubKey>::CalcScriptLen() const
Line
Count
Source
617
5.27M
    {
618
5.27M
        size_t subsize = 0;
619
5.27M
        for (const auto& sub : subs) {
620
5.27M
            subsize += sub.ScriptSize();
621
5.27M
        }
622
5.27M
        Type sub0type = subs.size() > 0 ? subs[0].GetType() : ""_mst;
623
5.27M
        return internal::ComputeScriptLen(fragment, sub0type, subsize, k, subs.size(), keys.size(), m_script_ctx);
624
5.27M
    }
625
626
    /* Apply a recursive algorithm to a Miniscript tree, without actual recursive calls.
627
     *
628
     * The algorithm is defined by two functions: downfn and upfn. Conceptually, the
629
     * result can be thought of as first using downfn to compute a "state" for each node,
630
     * from the root down to the leaves. Then upfn is used to compute a "result" for each
631
     * node, from the leaves back up to the root, which is then returned. In the actual
632
     * implementation, both functions are invoked in an interleaved fashion, performing a
633
     * depth-first traversal of the tree.
634
     *
635
     * In more detail, it is invoked as node.TreeEvalMaybe<Result>(root, downfn, upfn):
636
     * - root is the state of the root node, of type State.
637
     * - downfn is a callable (State&, const Node&, size_t) -> State, which given a
638
     *   node, its state, and an index of one of its children, computes the state of that
639
     *   child. It can modify the state. Children of a given node will have downfn()
640
     *   called in order.
641
     * - upfn is a callable (State&&, const Node&, std::span<Result>) -> std::optional<Result>,
642
     *   which given a node, its state, and a span of the results of its children,
643
     *   computes the result of the node. If std::nullopt is returned by upfn,
644
     *   TreeEvalMaybe() immediately returns std::nullopt.
645
     * The return value of TreeEvalMaybe is the result of the root node.
646
     *
647
     * Result type cannot be bool due to the std::vector<bool> specialization.
648
     */
649
    template<typename Result, typename State, typename DownFn, typename UpFn>
650
    std::optional<Result> TreeEvalMaybe(State root_state, DownFn downfn, UpFn upfn) const
651
15.9k
    {
652
        /** Entries of the explicit stack tracked in this algorithm. */
653
15.9k
        struct StackElem
654
15.9k
        {
655
15.9k
            const Node& node; //!< The node being evaluated.
656
15.9k
            size_t expanded; //!< How many children of this node have been expanded.
657
15.9k
            State state; //!< The state for that node.
658
659
15.9k
            StackElem(const Node& node_, size_t exp_, State&& state_) :
660
18.4M
                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
660
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
660
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
660
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
660
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
660
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
660
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
660
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
660
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
660
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
660
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
660
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
660
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
660
5.27M
                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
660
5.27M
                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
660
3.01k
                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
660
3.01k
                node(node_), expanded(exp_), state(std::move(state_)) {}
661
15.9k
        };
662
        /* Stack of tree nodes being explored. */
663
15.9k
        std::vector<StackElem> stack;
664
        /* Results of subtrees so far. Their order and mapping to tree nodes
665
         * is implicitly defined by stack. */
666
15.9k
        std::vector<Result> results;
667
15.9k
        stack.emplace_back(*this, 0, std::move(root_state));
668
669
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
670
         * State variables are omitted for simplicity.
671
         *
672
         * First: stack=[(A,0)] results=[]
673
         *        stack=[(A,1),(B,0)] results=[]
674
         *        stack=[(A,1)] results=[B]
675
         *        stack=[(A,2),(C,0)] results=[B]
676
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
677
         *        stack=[(A,2),(C,1)] results=[B,D]
678
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
679
         *        stack=[(A,2),(C,2)] results=[B,D,E]
680
         *        stack=[(A,2)] results=[B,C]
681
         *        stack=[(A,3),(F,0)] results=[B,C]
682
         *        stack=[(A,3)] results=[B,C,F]
683
         * Final: stack=[] results=[A]
684
         */
685
36.8M
        while (stack.size()) {
686
36.8M
            const Node& node = stack.back().node;
687
36.8M
            if (stack.back().expanded < node.subs.size()) {
688
                /* We encounter a tree node with at least one unexpanded child.
689
                 * Expand it. By the time we hit this node again, the result of
690
                 * that child (and all earlier children) will be at the end of `results`. */
691
18.4M
                size_t child_index = stack.back().expanded++;
692
18.4M
                State child_state = downfn(stack.back().state, node, child_index);
693
18.4M
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
694
18.4M
                continue;
695
18.4M
            }
696
            // Invoke upfn with the last node.subs.size() elements of results as input.
697
36.8M
            assert(results.size() >= node.subs.size());
698
18.4M
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
699
18.4M
                std::span<Result>{results}.last(node.subs.size()))};
700
            // If evaluation returns std::nullopt, abort immediately.
701
18.4M
            if (!result) return {};
702
            // Replace the last node.subs.size() elements of results with the new result.
703
18.4M
            results.erase(results.end() - node.subs.size(), results.end());
704
18.4M
            results.push_back(std::move(*result));
705
18.4M
            stack.pop_back();
706
18.4M
        }
707
        // The final remaining results element is the root result, return it.
708
15.9k
        assert(results.size() >= 1);
709
15.9k
        CHECK_NONFATAL(results.size() == 1);
710
15.9k
        return std::move(results[0]);
711
15.9k
    }
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
651
375
    {
652
        /** Entries of the explicit stack tracked in this algorithm. */
653
375
        struct StackElem
654
375
        {
655
375
            const Node& node; //!< The node being evaluated.
656
375
            size_t expanded; //!< How many children of this node have been expanded.
657
375
            State state; //!< The state for that node.
658
659
375
            StackElem(const Node& node_, size_t exp_, State&& state_) :
660
375
                node(node_), expanded(exp_), state(std::move(state_)) {}
661
375
        };
662
        /* Stack of tree nodes being explored. */
663
375
        std::vector<StackElem> stack;
664
        /* Results of subtrees so far. Their order and mapping to tree nodes
665
         * is implicitly defined by stack. */
666
375
        std::vector<Result> results;
667
375
        stack.emplace_back(*this, 0, std::move(root_state));
668
669
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
670
         * State variables are omitted for simplicity.
671
         *
672
         * First: stack=[(A,0)] results=[]
673
         *        stack=[(A,1),(B,0)] results=[]
674
         *        stack=[(A,1)] results=[B]
675
         *        stack=[(A,2),(C,0)] results=[B]
676
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
677
         *        stack=[(A,2),(C,1)] results=[B,D]
678
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
679
         *        stack=[(A,2),(C,2)] results=[B,D,E]
680
         *        stack=[(A,2)] results=[B,C]
681
         *        stack=[(A,3),(F,0)] results=[B,C]
682
         *        stack=[(A,3)] results=[B,C,F]
683
         * Final: stack=[] results=[A]
684
         */
685
50.8k
        while (stack.size()) {
686
50.4k
            const Node& node = stack.back().node;
687
50.4k
            if (stack.back().expanded < node.subs.size()) {
688
                /* We encounter a tree node with at least one unexpanded child.
689
                 * Expand it. By the time we hit this node again, the result of
690
                 * that child (and all earlier children) will be at the end of `results`. */
691
25.0k
                size_t child_index = stack.back().expanded++;
692
25.0k
                State child_state = downfn(stack.back().state, node, child_index);
693
25.0k
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
694
25.0k
                continue;
695
25.0k
            }
696
            // Invoke upfn with the last node.subs.size() elements of results as input.
697
50.4k
            assert(results.size() >= node.subs.size());
698
25.4k
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
699
25.4k
                std::span<Result>{results}.last(node.subs.size()))};
700
            // If evaluation returns std::nullopt, abort immediately.
701
25.4k
            if (!result) return {};
702
            // Replace the last node.subs.size() elements of results with the new result.
703
25.4k
            results.erase(results.end() - node.subs.size(), results.end());
704
25.4k
            results.push_back(std::move(*result));
705
25.4k
            stack.pop_back();
706
25.4k
        }
707
        // The final remaining results element is the root result, return it.
708
375
        assert(results.size() >= 1);
709
375
        CHECK_NONFATAL(results.size() == 1);
710
375
        return std::move(results[0]);
711
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
651
4.82k
    {
652
        /** Entries of the explicit stack tracked in this algorithm. */
653
4.82k
        struct StackElem
654
4.82k
        {
655
4.82k
            const Node& node; //!< The node being evaluated.
656
4.82k
            size_t expanded; //!< How many children of this node have been expanded.
657
4.82k
            State state; //!< The state for that node.
658
659
4.82k
            StackElem(const Node& node_, size_t exp_, State&& state_) :
660
4.82k
                node(node_), expanded(exp_), state(std::move(state_)) {}
661
4.82k
        };
662
        /* Stack of tree nodes being explored. */
663
4.82k
        std::vector<StackElem> stack;
664
        /* Results of subtrees so far. Their order and mapping to tree nodes
665
         * is implicitly defined by stack. */
666
4.82k
        std::vector<Result> results;
667
4.82k
        stack.emplace_back(*this, 0, std::move(root_state));
668
669
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
670
         * State variables are omitted for simplicity.
671
         *
672
         * First: stack=[(A,0)] results=[]
673
         *        stack=[(A,1),(B,0)] results=[]
674
         *        stack=[(A,1)] results=[B]
675
         *        stack=[(A,2),(C,0)] results=[B]
676
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
677
         *        stack=[(A,2),(C,1)] results=[B,D]
678
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
679
         *        stack=[(A,2),(C,2)] results=[B,D,E]
680
         *        stack=[(A,2)] results=[B,C]
681
         *        stack=[(A,3),(F,0)] results=[B,C]
682
         *        stack=[(A,3)] results=[B,C,F]
683
         * Final: stack=[] results=[A]
684
         */
685
3.23M
        while (stack.size()) {
686
3.22M
            const Node& node = stack.back().node;
687
3.22M
            if (stack.back().expanded < node.subs.size()) {
688
                /* We encounter a tree node with at least one unexpanded child.
689
                 * Expand it. By the time we hit this node again, the result of
690
                 * that child (and all earlier children) will be at the end of `results`. */
691
1.61M
                size_t child_index = stack.back().expanded++;
692
1.61M
                State child_state = downfn(stack.back().state, node, child_index);
693
1.61M
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
694
1.61M
                continue;
695
1.61M
            }
696
            // Invoke upfn with the last node.subs.size() elements of results as input.
697
3.22M
            assert(results.size() >= node.subs.size());
698
1.61M
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
699
1.61M
                std::span<Result>{results}.last(node.subs.size()))};
700
            // If evaluation returns std::nullopt, abort immediately.
701
1.61M
            if (!result) return {};
702
            // Replace the last node.subs.size() elements of results with the new result.
703
1.61M
            results.erase(results.end() - node.subs.size(), results.end());
704
1.61M
            results.push_back(std::move(*result));
705
1.61M
            stack.pop_back();
706
1.61M
        }
707
        // The final remaining results element is the root result, return it.
708
4.82k
        assert(results.size() >= 1);
709
4.82k
        CHECK_NONFATAL(results.size() == 1);
710
4.82k
        return std::move(results[0]);
711
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
651
375
    {
652
        /** Entries of the explicit stack tracked in this algorithm. */
653
375
        struct StackElem
654
375
        {
655
375
            const Node& node; //!< The node being evaluated.
656
375
            size_t expanded; //!< How many children of this node have been expanded.
657
375
            State state; //!< The state for that node.
658
659
375
            StackElem(const Node& node_, size_t exp_, State&& state_) :
660
375
                node(node_), expanded(exp_), state(std::move(state_)) {}
661
375
        };
662
        /* Stack of tree nodes being explored. */
663
375
        std::vector<StackElem> stack;
664
        /* Results of subtrees so far. Their order and mapping to tree nodes
665
         * is implicitly defined by stack. */
666
375
        std::vector<Result> results;
667
375
        stack.emplace_back(*this, 0, std::move(root_state));
668
669
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
670
         * State variables are omitted for simplicity.
671
         *
672
         * First: stack=[(A,0)] results=[]
673
         *        stack=[(A,1),(B,0)] results=[]
674
         *        stack=[(A,1)] results=[B]
675
         *        stack=[(A,2),(C,0)] results=[B]
676
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
677
         *        stack=[(A,2),(C,1)] results=[B,D]
678
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
679
         *        stack=[(A,2),(C,2)] results=[B,D,E]
680
         *        stack=[(A,2)] results=[B,C]
681
         *        stack=[(A,3),(F,0)] results=[B,C]
682
         *        stack=[(A,3)] results=[B,C,F]
683
         * Final: stack=[] results=[A]
684
         */
685
50.8k
        while (stack.size()) {
686
50.4k
            const Node& node = stack.back().node;
687
50.4k
            if (stack.back().expanded < node.subs.size()) {
688
                /* We encounter a tree node with at least one unexpanded child.
689
                 * Expand it. By the time we hit this node again, the result of
690
                 * that child (and all earlier children) will be at the end of `results`. */
691
25.0k
                size_t child_index = stack.back().expanded++;
692
25.0k
                State child_state = downfn(stack.back().state, node, child_index);
693
25.0k
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
694
25.0k
                continue;
695
25.0k
            }
696
            // Invoke upfn with the last node.subs.size() elements of results as input.
697
50.4k
            assert(results.size() >= node.subs.size());
698
25.4k
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
699
25.4k
                std::span<Result>{results}.last(node.subs.size()))};
700
            // If evaluation returns std::nullopt, abort immediately.
701
25.4k
            if (!result) return {};
702
            // Replace the last node.subs.size() elements of results with the new result.
703
25.4k
            results.erase(results.end() - node.subs.size(), results.end());
704
25.4k
            results.push_back(std::move(*result));
705
25.4k
            stack.pop_back();
706
25.4k
        }
707
        // The final remaining results element is the root result, return it.
708
375
        assert(results.size() >= 1);
709
375
        CHECK_NONFATAL(results.size() == 1);
710
375
        return std::move(results[0]);
711
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
651
313
    {
652
        /** Entries of the explicit stack tracked in this algorithm. */
653
313
        struct StackElem
654
313
        {
655
313
            const Node& node; //!< The node being evaluated.
656
313
            size_t expanded; //!< How many children of this node have been expanded.
657
313
            State state; //!< The state for that node.
658
659
313
            StackElem(const Node& node_, size_t exp_, State&& state_) :
660
313
                node(node_), expanded(exp_), state(std::move(state_)) {}
661
313
        };
662
        /* Stack of tree nodes being explored. */
663
313
        std::vector<StackElem> stack;
664
        /* Results of subtrees so far. Their order and mapping to tree nodes
665
         * is implicitly defined by stack. */
666
313
        std::vector<Result> results;
667
313
        stack.emplace_back(*this, 0, std::move(root_state));
668
669
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
670
         * State variables are omitted for simplicity.
671
         *
672
         * First: stack=[(A,0)] results=[]
673
         *        stack=[(A,1),(B,0)] results=[]
674
         *        stack=[(A,1)] results=[B]
675
         *        stack=[(A,2),(C,0)] results=[B]
676
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
677
         *        stack=[(A,2),(C,1)] results=[B,D]
678
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
679
         *        stack=[(A,2),(C,2)] results=[B,D,E]
680
         *        stack=[(A,2)] results=[B,C]
681
         *        stack=[(A,3),(F,0)] results=[B,C]
682
         *        stack=[(A,3)] results=[B,C,F]
683
         * Final: stack=[] results=[A]
684
         */
685
46.5k
        while (stack.size()) {
686
46.1k
            const Node& node = stack.back().node;
687
46.1k
            if (stack.back().expanded < node.subs.size()) {
688
                /* We encounter a tree node with at least one unexpanded child.
689
                 * Expand it. By the time we hit this node again, the result of
690
                 * that child (and all earlier children) will be at the end of `results`. */
691
22.9k
                size_t child_index = stack.back().expanded++;
692
22.9k
                State child_state = downfn(stack.back().state, node, child_index);
693
22.9k
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
694
22.9k
                continue;
695
22.9k
            }
696
            // Invoke upfn with the last node.subs.size() elements of results as input.
697
46.1k
            assert(results.size() >= node.subs.size());
698
23.2k
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
699
23.2k
                std::span<Result>{results}.last(node.subs.size()))};
700
            // If evaluation returns std::nullopt, abort immediately.
701
23.2k
            if (!result) return {};
702
            // Replace the last node.subs.size() elements of results with the new result.
703
23.2k
            results.erase(results.end() - node.subs.size(), results.end());
704
23.2k
            results.push_back(std::move(*result));
705
23.2k
            stack.pop_back();
706
23.2k
        }
707
        // The final remaining results element is the root result, return it.
708
313
        assert(results.size() >= 1);
709
313
        CHECK_NONFATAL(results.size() == 1);
710
313
        return std::move(results[0]);
711
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
651
1
    {
652
        /** Entries of the explicit stack tracked in this algorithm. */
653
1
        struct StackElem
654
1
        {
655
1
            const Node& node; //!< The node being evaluated.
656
1
            size_t expanded; //!< How many children of this node have been expanded.
657
1
            State state; //!< The state for that node.
658
659
1
            StackElem(const Node& node_, size_t exp_, State&& state_) :
660
1
                node(node_), expanded(exp_), state(std::move(state_)) {}
661
1
        };
662
        /* Stack of tree nodes being explored. */
663
1
        std::vector<StackElem> stack;
664
        /* Results of subtrees so far. Their order and mapping to tree nodes
665
         * is implicitly defined by stack. */
666
1
        std::vector<Result> results;
667
1
        stack.emplace_back(*this, 0, std::move(root_state));
668
669
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
670
         * State variables are omitted for simplicity.
671
         *
672
         * First: stack=[(A,0)] results=[]
673
         *        stack=[(A,1),(B,0)] results=[]
674
         *        stack=[(A,1)] results=[B]
675
         *        stack=[(A,2),(C,0)] results=[B]
676
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
677
         *        stack=[(A,2),(C,1)] results=[B,D]
678
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
679
         *        stack=[(A,2),(C,2)] results=[B,D,E]
680
         *        stack=[(A,2)] results=[B,C]
681
         *        stack=[(A,3),(F,0)] results=[B,C]
682
         *        stack=[(A,3)] results=[B,C,F]
683
         * Final: stack=[] results=[A]
684
         */
685
14
        while (stack.size()) {
686
13
            const Node& node = stack.back().node;
687
13
            if (stack.back().expanded < node.subs.size()) {
688
                /* We encounter a tree node with at least one unexpanded child.
689
                 * Expand it. By the time we hit this node again, the result of
690
                 * that child (and all earlier children) will be at the end of `results`. */
691
6
                size_t child_index = stack.back().expanded++;
692
6
                State child_state = downfn(stack.back().state, node, child_index);
693
6
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
694
6
                continue;
695
6
            }
696
            // Invoke upfn with the last node.subs.size() elements of results as input.
697
13
            assert(results.size() >= node.subs.size());
698
7
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
699
7
                std::span<Result>{results}.last(node.subs.size()))};
700
            // If evaluation returns std::nullopt, abort immediately.
701
7
            if (!result) return {};
702
            // Replace the last node.subs.size() elements of results with the new result.
703
7
            results.erase(results.end() - node.subs.size(), results.end());
704
7
            results.push_back(std::move(*result));
705
7
            stack.pop_back();
706
7
        }
707
        // The final remaining results element is the root result, return it.
708
1
        assert(results.size() >= 1);
709
1
        CHECK_NONFATAL(results.size() == 1);
710
1
        return std::move(results[0]);
711
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
651
1
    {
652
        /** Entries of the explicit stack tracked in this algorithm. */
653
1
        struct StackElem
654
1
        {
655
1
            const Node& node; //!< The node being evaluated.
656
1
            size_t expanded; //!< How many children of this node have been expanded.
657
1
            State state; //!< The state for that node.
658
659
1
            StackElem(const Node& node_, size_t exp_, State&& state_) :
660
1
                node(node_), expanded(exp_), state(std::move(state_)) {}
661
1
        };
662
        /* Stack of tree nodes being explored. */
663
1
        std::vector<StackElem> stack;
664
        /* Results of subtrees so far. Their order and mapping to tree nodes
665
         * is implicitly defined by stack. */
666
1
        std::vector<Result> results;
667
1
        stack.emplace_back(*this, 0, std::move(root_state));
668
669
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
670
         * State variables are omitted for simplicity.
671
         *
672
         * First: stack=[(A,0)] results=[]
673
         *        stack=[(A,1),(B,0)] results=[]
674
         *        stack=[(A,1)] results=[B]
675
         *        stack=[(A,2),(C,0)] results=[B]
676
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
677
         *        stack=[(A,2),(C,1)] results=[B,D]
678
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
679
         *        stack=[(A,2),(C,2)] results=[B,D,E]
680
         *        stack=[(A,2)] results=[B,C]
681
         *        stack=[(A,3),(F,0)] results=[B,C]
682
         *        stack=[(A,3)] results=[B,C,F]
683
         * Final: stack=[] results=[A]
684
         */
685
8
        while (stack.size()) {
686
7
            const Node& node = stack.back().node;
687
7
            if (stack.back().expanded < node.subs.size()) {
688
                /* We encounter a tree node with at least one unexpanded child.
689
                 * Expand it. By the time we hit this node again, the result of
690
                 * that child (and all earlier children) will be at the end of `results`. */
691
3
                size_t child_index = stack.back().expanded++;
692
3
                State child_state = downfn(stack.back().state, node, child_index);
693
3
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
694
3
                continue;
695
3
            }
696
            // Invoke upfn with the last node.subs.size() elements of results as input.
697
7
            assert(results.size() >= node.subs.size());
698
4
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
699
4
                std::span<Result>{results}.last(node.subs.size()))};
700
            // If evaluation returns std::nullopt, abort immediately.
701
4
            if (!result) return {};
702
            // Replace the last node.subs.size() elements of results with the new result.
703
4
            results.erase(results.end() - node.subs.size(), results.end());
704
4
            results.push_back(std::move(*result));
705
4
            stack.pop_back();
706
4
        }
707
        // The final remaining results element is the root result, return it.
708
1
        assert(results.size() >= 1);
709
1
        CHECK_NONFATAL(results.size() == 1);
710
1
        return std::move(results[0]);
711
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
651
190
    {
652
        /** Entries of the explicit stack tracked in this algorithm. */
653
190
        struct StackElem
654
190
        {
655
190
            const Node& node; //!< The node being evaluated.
656
190
            size_t expanded; //!< How many children of this node have been expanded.
657
190
            State state; //!< The state for that node.
658
659
190
            StackElem(const Node& node_, size_t exp_, State&& state_) :
660
190
                node(node_), expanded(exp_), state(std::move(state_)) {}
661
190
        };
662
        /* Stack of tree nodes being explored. */
663
190
        std::vector<StackElem> stack;
664
        /* Results of subtrees so far. Their order and mapping to tree nodes
665
         * is implicitly defined by stack. */
666
190
        std::vector<Result> results;
667
190
        stack.emplace_back(*this, 0, std::move(root_state));
668
669
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
670
         * State variables are omitted for simplicity.
671
         *
672
         * First: stack=[(A,0)] results=[]
673
         *        stack=[(A,1),(B,0)] results=[]
674
         *        stack=[(A,1)] results=[B]
675
         *        stack=[(A,2),(C,0)] results=[B]
676
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
677
         *        stack=[(A,2),(C,1)] results=[B,D]
678
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
679
         *        stack=[(A,2),(C,2)] results=[B,D,E]
680
         *        stack=[(A,2)] results=[B,C]
681
         *        stack=[(A,3),(F,0)] results=[B,C]
682
         *        stack=[(A,3)] results=[B,C,F]
683
         * Final: stack=[] results=[A]
684
         */
685
1.06M
        while (stack.size()) {
686
1.06M
            const Node& node = stack.back().node;
687
1.06M
            if (stack.back().expanded < node.subs.size()) {
688
                /* We encounter a tree node with at least one unexpanded child.
689
                 * Expand it. By the time we hit this node again, the result of
690
                 * that child (and all earlier children) will be at the end of `results`. */
691
530k
                size_t child_index = stack.back().expanded++;
692
530k
                State child_state = downfn(stack.back().state, node, child_index);
693
530k
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
694
530k
                continue;
695
530k
            }
696
            // Invoke upfn with the last node.subs.size() elements of results as input.
697
1.06M
            assert(results.size() >= node.subs.size());
698
531k
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
699
531k
                std::span<Result>{results}.last(node.subs.size()))};
700
            // If evaluation returns std::nullopt, abort immediately.
701
531k
            if (!result) return {};
702
            // Replace the last node.subs.size() elements of results with the new result.
703
531k
            results.erase(results.end() - node.subs.size(), results.end());
704
531k
            results.push_back(std::move(*result));
705
531k
            stack.pop_back();
706
531k
        }
707
        // The final remaining results element is the root result, return it.
708
190
        assert(results.size() >= 1);
709
190
        CHECK_NONFATAL(results.size() == 1);
710
190
        return std::move(results[0]);
711
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
651
791
    {
652
        /** Entries of the explicit stack tracked in this algorithm. */
653
791
        struct StackElem
654
791
        {
655
791
            const Node& node; //!< The node being evaluated.
656
791
            size_t expanded; //!< How many children of this node have been expanded.
657
791
            State state; //!< The state for that node.
658
659
791
            StackElem(const Node& node_, size_t exp_, State&& state_) :
660
791
                node(node_), expanded(exp_), state(std::move(state_)) {}
661
791
        };
662
        /* Stack of tree nodes being explored. */
663
791
        std::vector<StackElem> stack;
664
        /* Results of subtrees so far. Their order and mapping to tree nodes
665
         * is implicitly defined by stack. */
666
791
        std::vector<Result> results;
667
791
        stack.emplace_back(*this, 0, std::move(root_state));
668
669
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
670
         * State variables are omitted for simplicity.
671
         *
672
         * First: stack=[(A,0)] results=[]
673
         *        stack=[(A,1),(B,0)] results=[]
674
         *        stack=[(A,1)] results=[B]
675
         *        stack=[(A,2),(C,0)] results=[B]
676
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
677
         *        stack=[(A,2),(C,1)] results=[B,D]
678
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
679
         *        stack=[(A,2),(C,2)] results=[B,D,E]
680
         *        stack=[(A,2)] results=[B,C]
681
         *        stack=[(A,3),(F,0)] results=[B,C]
682
         *        stack=[(A,3)] results=[B,C,F]
683
         * Final: stack=[] results=[A]
684
         */
685
1.99M
        while (stack.size()) {
686
1.99M
            const Node& node = stack.back().node;
687
1.99M
            if (stack.back().expanded < node.subs.size()) {
688
                /* We encounter a tree node with at least one unexpanded child.
689
                 * Expand it. By the time we hit this node again, the result of
690
                 * that child (and all earlier children) will be at the end of `results`. */
691
994k
                size_t child_index = stack.back().expanded++;
692
994k
                State child_state = downfn(stack.back().state, node, child_index);
693
994k
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
694
994k
                continue;
695
994k
            }
696
            // Invoke upfn with the last node.subs.size() elements of results as input.
697
1.99M
            assert(results.size() >= node.subs.size());
698
995k
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
699
995k
                std::span<Result>{results}.last(node.subs.size()))};
700
            // If evaluation returns std::nullopt, abort immediately.
701
995k
            if (!result) return {};
702
            // Replace the last node.subs.size() elements of results with the new result.
703
995k
            results.erase(results.end() - node.subs.size(), results.end());
704
995k
            results.push_back(std::move(*result));
705
995k
            stack.pop_back();
706
995k
        }
707
        // The final remaining results element is the root result, return it.
708
791
        assert(results.size() >= 1);
709
791
        CHECK_NONFATAL(results.size() == 1);
710
791
        return std::move(results[0]);
711
791
    }
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
651
14
    {
652
        /** Entries of the explicit stack tracked in this algorithm. */
653
14
        struct StackElem
654
14
        {
655
14
            const Node& node; //!< The node being evaluated.
656
14
            size_t expanded; //!< How many children of this node have been expanded.
657
14
            State state; //!< The state for that node.
658
659
14
            StackElem(const Node& node_, size_t exp_, State&& state_) :
660
14
                node(node_), expanded(exp_), state(std::move(state_)) {}
661
14
        };
662
        /* Stack of tree nodes being explored. */
663
14
        std::vector<StackElem> stack;
664
        /* Results of subtrees so far. Their order and mapping to tree nodes
665
         * is implicitly defined by stack. */
666
14
        std::vector<Result> results;
667
14
        stack.emplace_back(*this, 0, std::move(root_state));
668
669
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
670
         * State variables are omitted for simplicity.
671
         *
672
         * First: stack=[(A,0)] results=[]
673
         *        stack=[(A,1),(B,0)] results=[]
674
         *        stack=[(A,1)] results=[B]
675
         *        stack=[(A,2),(C,0)] results=[B]
676
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
677
         *        stack=[(A,2),(C,1)] results=[B,D]
678
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
679
         *        stack=[(A,2),(C,2)] results=[B,D,E]
680
         *        stack=[(A,2)] results=[B,C]
681
         *        stack=[(A,3),(F,0)] results=[B,C]
682
         *        stack=[(A,3)] results=[B,C,F]
683
         * Final: stack=[] results=[A]
684
         */
685
214
        while (stack.size()) {
686
200
            const Node& node = stack.back().node;
687
200
            if (stack.back().expanded < node.subs.size()) {
688
                /* We encounter a tree node with at least one unexpanded child.
689
                 * Expand it. By the time we hit this node again, the result of
690
                 * that child (and all earlier children) will be at the end of `results`. */
691
93
                size_t child_index = stack.back().expanded++;
692
93
                State child_state = downfn(stack.back().state, node, child_index);
693
93
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
694
93
                continue;
695
93
            }
696
            // Invoke upfn with the last node.subs.size() elements of results as input.
697
200
            assert(results.size() >= node.subs.size());
698
107
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
699
107
                std::span<Result>{results}.last(node.subs.size()))};
700
            // If evaluation returns std::nullopt, abort immediately.
701
107
            if (!result) return {};
702
            // Replace the last node.subs.size() elements of results with the new result.
703
107
            results.erase(results.end() - node.subs.size(), results.end());
704
107
            results.push_back(std::move(*result));
705
107
            stack.pop_back();
706
107
        }
707
        // The final remaining results element is the root result, return it.
708
14
        assert(results.size() >= 1);
709
14
        CHECK_NONFATAL(results.size() == 1);
710
14
        return std::move(results[0]);
711
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
651
14
    {
652
        /** Entries of the explicit stack tracked in this algorithm. */
653
14
        struct StackElem
654
14
        {
655
14
            const Node& node; //!< The node being evaluated.
656
14
            size_t expanded; //!< How many children of this node have been expanded.
657
14
            State state; //!< The state for that node.
658
659
14
            StackElem(const Node& node_, size_t exp_, State&& state_) :
660
14
                node(node_), expanded(exp_), state(std::move(state_)) {}
661
14
        };
662
        /* Stack of tree nodes being explored. */
663
14
        std::vector<StackElem> stack;
664
        /* Results of subtrees so far. Their order and mapping to tree nodes
665
         * is implicitly defined by stack. */
666
14
        std::vector<Result> results;
667
14
        stack.emplace_back(*this, 0, std::move(root_state));
668
669
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
670
         * State variables are omitted for simplicity.
671
         *
672
         * First: stack=[(A,0)] results=[]
673
         *        stack=[(A,1),(B,0)] results=[]
674
         *        stack=[(A,1)] results=[B]
675
         *        stack=[(A,2),(C,0)] results=[B]
676
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
677
         *        stack=[(A,2),(C,1)] results=[B,D]
678
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
679
         *        stack=[(A,2),(C,2)] results=[B,D,E]
680
         *        stack=[(A,2)] results=[B,C]
681
         *        stack=[(A,3),(F,0)] results=[B,C]
682
         *        stack=[(A,3)] results=[B,C,F]
683
         * Final: stack=[] results=[A]
684
         */
685
158
        while (stack.size()) {
686
144
            const Node& node = stack.back().node;
687
144
            if (stack.back().expanded < node.subs.size()) {
688
                /* We encounter a tree node with at least one unexpanded child.
689
                 * Expand it. By the time we hit this node again, the result of
690
                 * that child (and all earlier children) will be at the end of `results`. */
691
65
                size_t child_index = stack.back().expanded++;
692
65
                State child_state = downfn(stack.back().state, node, child_index);
693
65
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
694
65
                continue;
695
65
            }
696
            // Invoke upfn with the last node.subs.size() elements of results as input.
697
144
            assert(results.size() >= node.subs.size());
698
79
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
699
79
                std::span<Result>{results}.last(node.subs.size()))};
700
            // If evaluation returns std::nullopt, abort immediately.
701
79
            if (!result) return {};
702
            // Replace the last node.subs.size() elements of results with the new result.
703
79
            results.erase(results.end() - node.subs.size(), results.end());
704
79
            results.push_back(std::move(*result));
705
79
            stack.pop_back();
706
79
        }
707
        // The final remaining results element is the root result, return it.
708
14
        assert(results.size() >= 1);
709
14
        CHECK_NONFATAL(results.size() == 1);
710
14
        return std::move(results[0]);
711
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
651
1.47k
    {
652
        /** Entries of the explicit stack tracked in this algorithm. */
653
1.47k
        struct StackElem
654
1.47k
        {
655
1.47k
            const Node& node; //!< The node being evaluated.
656
1.47k
            size_t expanded; //!< How many children of this node have been expanded.
657
1.47k
            State state; //!< The state for that node.
658
659
1.47k
            StackElem(const Node& node_, size_t exp_, State&& state_) :
660
1.47k
                node(node_), expanded(exp_), state(std::move(state_)) {}
661
1.47k
        };
662
        /* Stack of tree nodes being explored. */
663
1.47k
        std::vector<StackElem> stack;
664
        /* Results of subtrees so far. Their order and mapping to tree nodes
665
         * is implicitly defined by stack. */
666
1.47k
        std::vector<Result> results;
667
1.47k
        stack.emplace_back(*this, 0, std::move(root_state));
668
669
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
670
         * State variables are omitted for simplicity.
671
         *
672
         * First: stack=[(A,0)] results=[]
673
         *        stack=[(A,1),(B,0)] results=[]
674
         *        stack=[(A,1)] results=[B]
675
         *        stack=[(A,2),(C,0)] results=[B]
676
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
677
         *        stack=[(A,2),(C,1)] results=[B,D]
678
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
679
         *        stack=[(A,2),(C,2)] results=[B,D,E]
680
         *        stack=[(A,2)] results=[B,C]
681
         *        stack=[(A,3),(F,0)] results=[B,C]
682
         *        stack=[(A,3)] results=[B,C,F]
683
         * Final: stack=[] results=[A]
684
         */
685
3.32M
        while (stack.size()) {
686
3.32M
            const Node& node = stack.back().node;
687
3.32M
            if (stack.back().expanded < node.subs.size()) {
688
                /* We encounter a tree node with at least one unexpanded child.
689
                 * Expand it. By the time we hit this node again, the result of
690
                 * that child (and all earlier children) will be at the end of `results`. */
691
1.66M
                size_t child_index = stack.back().expanded++;
692
1.66M
                State child_state = downfn(stack.back().state, node, child_index);
693
1.66M
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
694
1.66M
                continue;
695
1.66M
            }
696
            // Invoke upfn with the last node.subs.size() elements of results as input.
697
3.32M
            assert(results.size() >= node.subs.size());
698
1.66M
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
699
1.66M
                std::span<Result>{results}.last(node.subs.size()))};
700
            // If evaluation returns std::nullopt, abort immediately.
701
1.66M
            if (!result) return {};
702
            // Replace the last node.subs.size() elements of results with the new result.
703
1.66M
            results.erase(results.end() - node.subs.size(), results.end());
704
1.66M
            results.push_back(std::move(*result));
705
1.66M
            stack.pop_back();
706
1.66M
        }
707
        // The final remaining results element is the root result, return it.
708
1.47k
        assert(results.size() >= 1);
709
1.47k
        CHECK_NONFATAL(results.size() == 1);
710
1.47k
        return std::move(results[0]);
711
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
651
1.08k
    {
652
        /** Entries of the explicit stack tracked in this algorithm. */
653
1.08k
        struct StackElem
654
1.08k
        {
655
1.08k
            const Node& node; //!< The node being evaluated.
656
1.08k
            size_t expanded; //!< How many children of this node have been expanded.
657
1.08k
            State state; //!< The state for that node.
658
659
1.08k
            StackElem(const Node& node_, size_t exp_, State&& state_) :
660
1.08k
                node(node_), expanded(exp_), state(std::move(state_)) {}
661
1.08k
        };
662
        /* Stack of tree nodes being explored. */
663
1.08k
        std::vector<StackElem> stack;
664
        /* Results of subtrees so far. Their order and mapping to tree nodes
665
         * is implicitly defined by stack. */
666
1.08k
        std::vector<Result> results;
667
1.08k
        stack.emplace_back(*this, 0, std::move(root_state));
668
669
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
670
         * State variables are omitted for simplicity.
671
         *
672
         * First: stack=[(A,0)] results=[]
673
         *        stack=[(A,1),(B,0)] results=[]
674
         *        stack=[(A,1)] results=[B]
675
         *        stack=[(A,2),(C,0)] results=[B]
676
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
677
         *        stack=[(A,2),(C,1)] results=[B,D]
678
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
679
         *        stack=[(A,2),(C,2)] results=[B,D,E]
680
         *        stack=[(A,2)] results=[B,C]
681
         *        stack=[(A,3),(F,0)] results=[B,C]
682
         *        stack=[(A,3)] results=[B,C,F]
683
         * Final: stack=[] results=[A]
684
         */
685
5.95M
        while (stack.size()) {
686
5.95M
            const Node& node = stack.back().node;
687
5.95M
            if (stack.back().expanded < node.subs.size()) {
688
                /* We encounter a tree node with at least one unexpanded child.
689
                 * Expand it. By the time we hit this node again, the result of
690
                 * that child (and all earlier children) will be at the end of `results`. */
691
2.97M
                size_t child_index = stack.back().expanded++;
692
2.97M
                State child_state = downfn(stack.back().state, node, child_index);
693
2.97M
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
694
2.97M
                continue;
695
2.97M
            }
696
            // Invoke upfn with the last node.subs.size() elements of results as input.
697
5.95M
            assert(results.size() >= node.subs.size());
698
2.97M
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
699
2.97M
                std::span<Result>{results}.last(node.subs.size()))};
700
            // If evaluation returns std::nullopt, abort immediately.
701
2.97M
            if (!result) return {};
702
            // Replace the last node.subs.size() elements of results with the new result.
703
2.97M
            results.erase(results.end() - node.subs.size(), results.end());
704
2.97M
            results.push_back(std::move(*result));
705
2.97M
            stack.pop_back();
706
2.97M
        }
707
        // The final remaining results element is the root result, return it.
708
1.08k
        assert(results.size() >= 1);
709
1.08k
        CHECK_NONFATAL(results.size() == 1);
710
1.08k
        return std::move(results[0]);
711
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
651
3.05k
    {
652
        /** Entries of the explicit stack tracked in this algorithm. */
653
3.05k
        struct StackElem
654
3.05k
        {
655
3.05k
            const Node& node; //!< The node being evaluated.
656
3.05k
            size_t expanded; //!< How many children of this node have been expanded.
657
3.05k
            State state; //!< The state for that node.
658
659
3.05k
            StackElem(const Node& node_, size_t exp_, State&& state_) :
660
3.05k
                node(node_), expanded(exp_), state(std::move(state_)) {}
661
3.05k
        };
662
        /* Stack of tree nodes being explored. */
663
3.05k
        std::vector<StackElem> stack;
664
        /* Results of subtrees so far. Their order and mapping to tree nodes
665
         * is implicitly defined by stack. */
666
3.05k
        std::vector<Result> results;
667
3.05k
        stack.emplace_back(*this, 0, std::move(root_state));
668
669
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
670
         * State variables are omitted for simplicity.
671
         *
672
         * First: stack=[(A,0)] results=[]
673
         *        stack=[(A,1),(B,0)] results=[]
674
         *        stack=[(A,1)] results=[B]
675
         *        stack=[(A,2),(C,0)] results=[B]
676
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
677
         *        stack=[(A,2),(C,1)] results=[B,D]
678
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
679
         *        stack=[(A,2),(C,2)] results=[B,D,E]
680
         *        stack=[(A,2)] results=[B,C]
681
         *        stack=[(A,3),(F,0)] results=[B,C]
682
         *        stack=[(A,3)] results=[B,C,F]
683
         * Final: stack=[] results=[A]
684
         */
685
10.5M
        while (stack.size()) {
686
10.5M
            const Node& node = stack.back().node;
687
10.5M
            if (stack.back().expanded < node.subs.size()) {
688
                /* We encounter a tree node with at least one unexpanded child.
689
                 * Expand it. By the time we hit this node again, the result of
690
                 * that child (and all earlier children) will be at the end of `results`. */
691
5.27M
                size_t child_index = stack.back().expanded++;
692
5.27M
                State child_state = downfn(stack.back().state, node, child_index);
693
5.27M
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
694
5.27M
                continue;
695
5.27M
            }
696
            // Invoke upfn with the last node.subs.size() elements of results as input.
697
10.5M
            assert(results.size() >= node.subs.size());
698
5.27M
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
699
5.27M
                std::span<Result>{results}.last(node.subs.size()))};
700
            // If evaluation returns std::nullopt, abort immediately.
701
5.27M
            if (!result) return {};
702
            // Replace the last node.subs.size() elements of results with the new result.
703
5.27M
            results.erase(results.end() - node.subs.size(), results.end());
704
5.27M
            results.push_back(std::move(*result));
705
5.27M
            stack.pop_back();
706
5.27M
        }
707
        // The final remaining results element is the root result, return it.
708
3.05k
        assert(results.size() >= 1);
709
3.05k
        CHECK_NONFATAL(results.size() == 1);
710
3.05k
        return std::move(results[0]);
711
3.05k
    }
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
651
3.05k
    {
652
        /** Entries of the explicit stack tracked in this algorithm. */
653
3.05k
        struct StackElem
654
3.05k
        {
655
3.05k
            const Node& node; //!< The node being evaluated.
656
3.05k
            size_t expanded; //!< How many children of this node have been expanded.
657
3.05k
            State state; //!< The state for that node.
658
659
3.05k
            StackElem(const Node& node_, size_t exp_, State&& state_) :
660
3.05k
                node(node_), expanded(exp_), state(std::move(state_)) {}
661
3.05k
        };
662
        /* Stack of tree nodes being explored. */
663
3.05k
        std::vector<StackElem> stack;
664
        /* Results of subtrees so far. Their order and mapping to tree nodes
665
         * is implicitly defined by stack. */
666
3.05k
        std::vector<Result> results;
667
3.05k
        stack.emplace_back(*this, 0, std::move(root_state));
668
669
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
670
         * State variables are omitted for simplicity.
671
         *
672
         * First: stack=[(A,0)] results=[]
673
         *        stack=[(A,1),(B,0)] results=[]
674
         *        stack=[(A,1)] results=[B]
675
         *        stack=[(A,2),(C,0)] results=[B]
676
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
677
         *        stack=[(A,2),(C,1)] results=[B,D]
678
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
679
         *        stack=[(A,2),(C,2)] results=[B,D,E]
680
         *        stack=[(A,2)] results=[B,C]
681
         *        stack=[(A,3),(F,0)] results=[B,C]
682
         *        stack=[(A,3)] results=[B,C,F]
683
         * Final: stack=[] results=[A]
684
         */
685
10.5M
        while (stack.size()) {
686
10.5M
            const Node& node = stack.back().node;
687
10.5M
            if (stack.back().expanded < node.subs.size()) {
688
                /* We encounter a tree node with at least one unexpanded child.
689
                 * Expand it. By the time we hit this node again, the result of
690
                 * that child (and all earlier children) will be at the end of `results`. */
691
5.27M
                size_t child_index = stack.back().expanded++;
692
5.27M
                State child_state = downfn(stack.back().state, node, child_index);
693
5.27M
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
694
5.27M
                continue;
695
5.27M
            }
696
            // Invoke upfn with the last node.subs.size() elements of results as input.
697
10.5M
            assert(results.size() >= node.subs.size());
698
5.27M
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
699
5.27M
                std::span<Result>{results}.last(node.subs.size()))};
700
            // If evaluation returns std::nullopt, abort immediately.
701
5.27M
            if (!result) return {};
702
            // Replace the last node.subs.size() elements of results with the new result.
703
5.27M
            results.erase(results.end() - node.subs.size(), results.end());
704
5.27M
            results.push_back(std::move(*result));
705
5.27M
            stack.pop_back();
706
5.27M
        }
707
        // The final remaining results element is the root result, return it.
708
3.05k
        assert(results.size() >= 1);
709
3.05k
        CHECK_NONFATAL(results.size() == 1);
710
3.05k
        return std::move(results[0]);
711
3.05k
    }
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
651
213
    {
652
        /** Entries of the explicit stack tracked in this algorithm. */
653
213
        struct StackElem
654
213
        {
655
213
            const Node& node; //!< The node being evaluated.
656
213
            size_t expanded; //!< How many children of this node have been expanded.
657
213
            State state; //!< The state for that node.
658
659
213
            StackElem(const Node& node_, size_t exp_, State&& state_) :
660
213
                node(node_), expanded(exp_), state(std::move(state_)) {}
661
213
        };
662
        /* Stack of tree nodes being explored. */
663
213
        std::vector<StackElem> stack;
664
        /* Results of subtrees so far. Their order and mapping to tree nodes
665
         * is implicitly defined by stack. */
666
213
        std::vector<Result> results;
667
213
        stack.emplace_back(*this, 0, std::move(root_state));
668
669
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
670
         * State variables are omitted for simplicity.
671
         *
672
         * First: stack=[(A,0)] results=[]
673
         *        stack=[(A,1),(B,0)] results=[]
674
         *        stack=[(A,1)] results=[B]
675
         *        stack=[(A,2),(C,0)] results=[B]
676
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
677
         *        stack=[(A,2),(C,1)] results=[B,D]
678
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
679
         *        stack=[(A,2),(C,2)] results=[B,D,E]
680
         *        stack=[(A,2)] results=[B,C]
681
         *        stack=[(A,3),(F,0)] results=[B,C]
682
         *        stack=[(A,3)] results=[B,C,F]
683
         * Final: stack=[] results=[A]
684
         */
685
6.02k
        while (stack.size()) {
686
5.80k
            const Node& node = stack.back().node;
687
5.80k
            if (stack.back().expanded < node.subs.size()) {
688
                /* We encounter a tree node with at least one unexpanded child.
689
                 * Expand it. By the time we hit this node again, the result of
690
                 * that child (and all earlier children) will be at the end of `results`. */
691
2.79k
                size_t child_index = stack.back().expanded++;
692
2.79k
                State child_state = downfn(stack.back().state, node, child_index);
693
2.79k
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
694
2.79k
                continue;
695
2.79k
            }
696
            // Invoke upfn with the last node.subs.size() elements of results as input.
697
5.80k
            assert(results.size() >= node.subs.size());
698
3.01k
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
699
3.01k
                std::span<Result>{results}.last(node.subs.size()))};
700
            // If evaluation returns std::nullopt, abort immediately.
701
3.01k
            if (!result) return {};
702
            // Replace the last node.subs.size() elements of results with the new result.
703
3.01k
            results.erase(results.end() - node.subs.size(), results.end());
704
3.01k
            results.push_back(std::move(*result));
705
3.01k
            stack.pop_back();
706
3.01k
        }
707
        // The final remaining results element is the root result, return it.
708
213
        assert(results.size() >= 1);
709
213
        CHECK_NONFATAL(results.size() == 1);
710
213
        return std::move(results[0]);
711
213
    }
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
651
213
    {
652
        /** Entries of the explicit stack tracked in this algorithm. */
653
213
        struct StackElem
654
213
        {
655
213
            const Node& node; //!< The node being evaluated.
656
213
            size_t expanded; //!< How many children of this node have been expanded.
657
213
            State state; //!< The state for that node.
658
659
213
            StackElem(const Node& node_, size_t exp_, State&& state_) :
660
213
                node(node_), expanded(exp_), state(std::move(state_)) {}
661
213
        };
662
        /* Stack of tree nodes being explored. */
663
213
        std::vector<StackElem> stack;
664
        /* Results of subtrees so far. Their order and mapping to tree nodes
665
         * is implicitly defined by stack. */
666
213
        std::vector<Result> results;
667
213
        stack.emplace_back(*this, 0, std::move(root_state));
668
669
        /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
670
         * State variables are omitted for simplicity.
671
         *
672
         * First: stack=[(A,0)] results=[]
673
         *        stack=[(A,1),(B,0)] results=[]
674
         *        stack=[(A,1)] results=[B]
675
         *        stack=[(A,2),(C,0)] results=[B]
676
         *        stack=[(A,2),(C,1),(D,0)] results=[B]
677
         *        stack=[(A,2),(C,1)] results=[B,D]
678
         *        stack=[(A,2),(C,2),(E,0)] results=[B,D]
679
         *        stack=[(A,2),(C,2)] results=[B,D,E]
680
         *        stack=[(A,2)] results=[B,C]
681
         *        stack=[(A,3),(F,0)] results=[B,C]
682
         *        stack=[(A,3)] results=[B,C,F]
683
         * Final: stack=[] results=[A]
684
         */
685
6.02k
        while (stack.size()) {
686
5.80k
            const Node& node = stack.back().node;
687
5.80k
            if (stack.back().expanded < node.subs.size()) {
688
                /* We encounter a tree node with at least one unexpanded child.
689
                 * Expand it. By the time we hit this node again, the result of
690
                 * that child (and all earlier children) will be at the end of `results`. */
691
2.79k
                size_t child_index = stack.back().expanded++;
692
2.79k
                State child_state = downfn(stack.back().state, node, child_index);
693
2.79k
                stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
694
2.79k
                continue;
695
2.79k
            }
696
            // Invoke upfn with the last node.subs.size() elements of results as input.
697
5.80k
            assert(results.size() >= node.subs.size());
698
3.01k
            std::optional<Result> result{upfn(std::move(stack.back().state), node,
699
3.01k
                std::span<Result>{results}.last(node.subs.size()))};
700
            // If evaluation returns std::nullopt, abort immediately.
701
3.01k
            if (!result) return {};
702
            // Replace the last node.subs.size() elements of results with the new result.
703
3.01k
            results.erase(results.end() - node.subs.size(), results.end());
704
3.01k
            results.push_back(std::move(*result));
705
3.01k
            stack.pop_back();
706
3.01k
        }
707
        // The final remaining results element is the root result, return it.
708
213
        assert(results.size() >= 1);
709
213
        CHECK_NONFATAL(results.size() == 1);
710
213
        return std::move(results[0]);
711
213
    }
712
713
    /** Like TreeEvalMaybe, but without downfn or State type.
714
     * upfn takes (const Node&, std::span<Result>) and returns std::optional<Result>. */
715
    template<typename Result, typename UpFn>
716
    std::optional<Result> TreeEvalMaybe(UpFn upfn) const
717
    {
718
        struct DummyState {};
719
        return TreeEvalMaybe<Result>(DummyState{},
720
            [](DummyState, const Node&, size_t) { return DummyState{}; },
721
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
722
                return upfn(node, subs);
723
            }
724
        );
725
    }
726
727
    /** Like TreeEvalMaybe, but always produces a result. upfn must return Result. */
728
    template<typename Result, typename State, typename DownFn, typename UpFn>
729
    Result TreeEval(State root_state, DownFn&& downfn, UpFn upfn) const
730
1.84k
    {
731
        // Invoke TreeEvalMaybe with upfn wrapped to return std::optional<Result>, and then
732
        // unconditionally dereference the result (it cannot be std::nullopt).
733
1.84k
        return std::move(*TreeEvalMaybe<Result>(std::move(root_state),
734
1.84k
            std::forward<DownFn>(downfn),
735
1.68M
            [&upfn](State&& state, const Node& node, std::span<Result> subs) {
736
1.68M
                Result res{upfn(std::move(state), node, subs)};
737
1.68M
                return std::optional<Result>(std::move(res));
738
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
735
25.4k
            [&upfn](State&& state, const Node& node, std::span<Result> subs) {
736
25.4k
                Result res{upfn(std::move(state), node, subs)};
737
25.4k
                return std::optional<Result>(std::move(res));
738
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
735
1.66M
            [&upfn](State&& state, const Node& node, std::span<Result> subs) {
736
1.66M
                Result res{upfn(std::move(state), node, subs)};
737
1.66M
                return std::optional<Result>(std::move(res));
738
1.66M
            }
739
1.84k
        ));
740
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
730
375
    {
731
        // Invoke TreeEvalMaybe with upfn wrapped to return std::optional<Result>, and then
732
        // unconditionally dereference the result (it cannot be std::nullopt).
733
375
        return std::move(*TreeEvalMaybe<Result>(std::move(root_state),
734
375
            std::forward<DownFn>(downfn),
735
375
            [&upfn](State&& state, const Node& node, std::span<Result> subs) {
736
375
                Result res{upfn(std::move(state), node, subs)};
737
375
                return std::optional<Result>(std::move(res));
738
375
            }
739
375
        ));
740
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
730
1.47k
    {
731
        // Invoke TreeEvalMaybe with upfn wrapped to return std::optional<Result>, and then
732
        // unconditionally dereference the result (it cannot be std::nullopt).
733
1.47k
        return std::move(*TreeEvalMaybe<Result>(std::move(root_state),
734
1.47k
            std::forward<DownFn>(downfn),
735
1.47k
            [&upfn](State&& state, const Node& node, std::span<Result> subs) {
736
1.47k
                Result res{upfn(std::move(state), node, subs)};
737
1.47k
                return std::optional<Result>(std::move(res));
738
1.47k
            }
739
1.47k
        ));
740
1.47k
    }
741
742
    /** Like TreeEval, but without downfn or State type.
743
     *  upfn takes (const Node&, std::span<Result>) and returns Result. */
744
    template<typename Result, typename UpFn>
745
    Result TreeEval(UpFn upfn) const
746
13.0k
    {
747
13.0k
        struct DummyState {};
748
13.0k
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
749
13.7M
            [](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
749
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
749
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
749
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
749
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
749
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
749
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
749
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
749
5.27M
            [](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
749
5.27M
            [](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
749
2.79k
            [](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
749
2.79k
            [](DummyState, const Node&, size_t) { return DummyState{}; },
750
13.7M
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
751
13.7M
                Result res{upfn(node, subs)};
752
13.7M
                return std::optional<Result>(std::move(res));
753
13.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
750
1.61M
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
751
1.61M
                Result res{upfn(node, subs)};
752
1.61M
                return std::optional<Result>(std::move(res));
753
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
750
25.4k
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
751
25.4k
                Result res{upfn(node, subs)};
752
25.4k
                return std::optional<Result>(std::move(res));
753
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
750
23.2k
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
751
23.2k
                Result res{upfn(node, subs)};
752
23.2k
                return std::optional<Result>(std::move(res));
753
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
750
7
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
751
7
                Result res{upfn(node, subs)};
752
7
                return std::optional<Result>(std::move(res));
753
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
750
531k
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
751
531k
                Result res{upfn(node, subs)};
752
531k
                return std::optional<Result>(std::move(res));
753
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
750
995k
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
751
995k
                Result res{upfn(node, subs)};
752
995k
                return std::optional<Result>(std::move(res));
753
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
750
107
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
751
107
                Result res{upfn(node, subs)};
752
107
                return std::optional<Result>(std::move(res));
753
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
750
5.27M
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
751
5.27M
                Result res{upfn(node, subs)};
752
5.27M
                return std::optional<Result>(std::move(res));
753
5.27M
            }
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
750
5.27M
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
751
5.27M
                Result res{upfn(node, subs)};
752
5.27M
                return std::optional<Result>(std::move(res));
753
5.27M
            }
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
750
3.01k
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
751
3.01k
                Result res{upfn(node, subs)};
752
3.01k
                return std::optional<Result>(std::move(res));
753
3.01k
            }
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
750
3.01k
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
751
3.01k
                Result res{upfn(node, subs)};
752
3.01k
                return std::optional<Result>(std::move(res));
753
3.01k
            }
754
13.0k
        ));
755
13.0k
    }
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
746
4.82k
    {
747
4.82k
        struct DummyState {};
748
4.82k
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
749
4.82k
            [](DummyState, const Node&, size_t) { return DummyState{}; },
750
4.82k
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
751
4.82k
                Result res{upfn(node, subs)};
752
4.82k
                return std::optional<Result>(std::move(res));
753
4.82k
            }
754
4.82k
        ));
755
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
746
375
    {
747
375
        struct DummyState {};
748
375
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
749
375
            [](DummyState, const Node&, size_t) { return DummyState{}; },
750
375
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
751
375
                Result res{upfn(node, subs)};
752
375
                return std::optional<Result>(std::move(res));
753
375
            }
754
375
        ));
755
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
746
313
    {
747
313
        struct DummyState {};
748
313
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
749
313
            [](DummyState, const Node&, size_t) { return DummyState{}; },
750
313
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
751
313
                Result res{upfn(node, subs)};
752
313
                return std::optional<Result>(std::move(res));
753
313
            }
754
313
        ));
755
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
746
1
    {
747
1
        struct DummyState {};
748
1
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
749
1
            [](DummyState, const Node&, size_t) { return DummyState{}; },
750
1
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
751
1
                Result res{upfn(node, subs)};
752
1
                return std::optional<Result>(std::move(res));
753
1
            }
754
1
        ));
755
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
746
190
    {
747
190
        struct DummyState {};
748
190
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
749
190
            [](DummyState, const Node&, size_t) { return DummyState{}; },
750
190
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
751
190
                Result res{upfn(node, subs)};
752
190
                return std::optional<Result>(std::move(res));
753
190
            }
754
190
        ));
755
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
746
791
    {
747
791
        struct DummyState {};
748
791
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
749
791
            [](DummyState, const Node&, size_t) { return DummyState{}; },
750
791
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
751
791
                Result res{upfn(node, subs)};
752
791
                return std::optional<Result>(std::move(res));
753
791
            }
754
791
        ));
755
791
    }
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
746
14
    {
747
14
        struct DummyState {};
748
14
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
749
14
            [](DummyState, const Node&, size_t) { return DummyState{}; },
750
14
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
751
14
                Result res{upfn(node, subs)};
752
14
                return std::optional<Result>(std::move(res));
753
14
            }
754
14
        ));
755
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
746
3.05k
    {
747
3.05k
        struct DummyState {};
748
3.05k
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
749
3.05k
            [](DummyState, const Node&, size_t) { return DummyState{}; },
750
3.05k
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
751
3.05k
                Result res{upfn(node, subs)};
752
3.05k
                return std::optional<Result>(std::move(res));
753
3.05k
            }
754
3.05k
        ));
755
3.05k
    }
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
746
3.05k
    {
747
3.05k
        struct DummyState {};
748
3.05k
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
749
3.05k
            [](DummyState, const Node&, size_t) { return DummyState{}; },
750
3.05k
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
751
3.05k
                Result res{upfn(node, subs)};
752
3.05k
                return std::optional<Result>(std::move(res));
753
3.05k
            }
754
3.05k
        ));
755
3.05k
    }
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
746
213
    {
747
213
        struct DummyState {};
748
213
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
749
213
            [](DummyState, const Node&, size_t) { return DummyState{}; },
750
213
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
751
213
                Result res{upfn(node, subs)};
752
213
                return std::optional<Result>(std::move(res));
753
213
            }
754
213
        ));
755
213
    }
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
746
213
    {
747
213
        struct DummyState {};
748
213
        return std::move(*TreeEvalMaybe<Result>(DummyState{},
749
213
            [](DummyState, const Node&, size_t) { return DummyState{}; },
750
213
            [&upfn](DummyState, const Node& node, std::span<Result> subs) {
751
213
                Result res{upfn(node, subs)};
752
213
                return std::optional<Result>(std::move(res));
753
213
            }
754
213
        ));
755
213
    }
756
757
    /** Compare two miniscript subtrees, using a non-recursive algorithm. */
758
    friend int Compare(const Node<Key>& node1, const Node<Key>& node2)
759
    {
760
        std::vector<std::pair<const Node<Key>&, const Node<Key>&>> queue;
761
        queue.emplace_back(node1, node2);
762
        while (!queue.empty()) {
763
            const auto& [a, b] = queue.back();
764
            queue.pop_back();
765
            if (std::tie(a.fragment, a.k, a.keys, a.data) < std::tie(b.fragment, b.k, b.keys, b.data)) return -1;
766
            if (std::tie(b.fragment, b.k, b.keys, b.data) < std::tie(a.fragment, a.k, a.keys, a.data)) return 1;
767
            if (a.subs.size() < b.subs.size()) return -1;
768
            if (b.subs.size() < a.subs.size()) return 1;
769
            size_t n = a.subs.size();
770
            for (size_t i = 0; i < n; ++i) {
771
                queue.emplace_back(a.subs[n - 1 - i], b.subs[n - 1 - i]);
772
            }
773
        }
774
        return 0;
775
    }
776
777
    //! Compute the type for this miniscript.
778
7.03M
    Type CalcType() const {
779
7.03M
        using namespace internal;
780
781
        // THRESH has a variable number of subexpressions
782
7.03M
        std::vector<Type> sub_types;
783
7.03M
        if (fragment == Fragment::THRESH) {
784
1.56k
            for (const auto& sub : subs) sub_types.push_back(sub.GetType());
785
404
        }
786
        // All other nodes than THRESH can be computed just from the types of the 0-3 subexpressions.
787
7.03M
        Type x = subs.size() > 0 ? subs[0].GetType() : ""_mst;
788
7.03M
        Type y = subs.size() > 1 ? subs[1].GetType() : ""_mst;
789
7.03M
        Type z = subs.size() > 2 ? subs[2].GetType() : ""_mst;
790
791
7.03M
        return SanitizeType(ComputeType(fragment, x, y, z, sub_types, k, data.size(), subs.size(), keys.size(), m_script_ctx));
792
7.03M
    }
miniscript::Node<CPubKey>::CalcType() const
Line
Count
Source
778
28.2k
    Type CalcType() const {
779
28.2k
        using namespace internal;
780
781
        // THRESH has a variable number of subexpressions
782
28.2k
        std::vector<Type> sub_types;
783
28.2k
        if (fragment == Fragment::THRESH) {
784
679
            for (const auto& sub : subs) sub_types.push_back(sub.GetType());
785
140
        }
786
        // All other nodes than THRESH can be computed just from the types of the 0-3 subexpressions.
787
28.2k
        Type x = subs.size() > 0 ? subs[0].GetType() : ""_mst;
788
28.2k
        Type y = subs.size() > 1 ? subs[1].GetType() : ""_mst;
789
28.2k
        Type z = subs.size() > 2 ? subs[2].GetType() : ""_mst;
790
791
28.2k
        return SanitizeType(ComputeType(fragment, x, y, z, sub_types, k, data.size(), subs.size(), keys.size(), m_script_ctx));
792
28.2k
    }
miniscript::Node<unsigned int>::CalcType() const
Line
Count
Source
778
1.72M
    Type CalcType() const {
779
1.72M
        using namespace internal;
780
781
        // THRESH has a variable number of subexpressions
782
1.72M
        std::vector<Type> sub_types;
783
1.72M
        if (fragment == Fragment::THRESH) {
784
828
            for (const auto& sub : subs) sub_types.push_back(sub.GetType());
785
246
        }
786
        // All other nodes than THRESH can be computed just from the types of the 0-3 subexpressions.
787
1.72M
        Type x = subs.size() > 0 ? subs[0].GetType() : ""_mst;
788
1.72M
        Type y = subs.size() > 1 ? subs[1].GetType() : ""_mst;
789
1.72M
        Type z = subs.size() > 2 ? subs[2].GetType() : ""_mst;
790
791
1.72M
        return SanitizeType(ComputeType(fragment, x, y, z, sub_types, k, data.size(), subs.size(), keys.size(), m_script_ctx));
792
1.72M
    }
miniscript::Node<XOnlyPubKey>::CalcType() const
Line
Count
Source
778
5.27M
    Type CalcType() const {
779
5.27M
        using namespace internal;
780
781
        // THRESH has a variable number of subexpressions
782
5.27M
        std::vector<Type> sub_types;
783
5.27M
        if (fragment == Fragment::THRESH) {
784
54
            for (const auto& sub : subs) sub_types.push_back(sub.GetType());
785
18
        }
786
        // All other nodes than THRESH can be computed just from the types of the 0-3 subexpressions.
787
5.27M
        Type x = subs.size() > 0 ? subs[0].GetType() : ""_mst;
788
5.27M
        Type y = subs.size() > 1 ? subs[1].GetType() : ""_mst;
789
5.27M
        Type z = subs.size() > 2 ? subs[2].GetType() : ""_mst;
790
791
5.27M
        return SanitizeType(ComputeType(fragment, x, y, z, sub_types, k, data.size(), subs.size(), keys.size(), m_script_ctx));
792
5.27M
    }
793
794
public:
795
    template<typename Ctx>
796
    CScript ToScript(const Ctx& ctx) const
797
1.84k
    {
798
        // To construct the CScript for a Miniscript object, we use the TreeEval algorithm.
799
        // The State is a boolean: whether or not the node's script expansion is followed
800
        // by an OP_VERIFY (which may need to be combined with the last script opcode).
801
1.68M
        auto downfn = [](bool verify, const Node& node, size_t index) {
802
            // For WRAP_V, the subexpression is certainly followed by OP_VERIFY.
803
1.68M
            if (node.fragment == Fragment::WRAP_V) return true;
804
            // The subexpression of WRAP_S, and the last subexpression of AND_V
805
            // inherit the followed-by-OP_VERIFY property from the parent.
806
1.68M
            if (node.fragment == Fragment::WRAP_S ||
807
1.68M
                (node.fragment == Fragment::AND_V && index == 1)) return verify;
808
1.68M
            return false;
809
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
801
25.0k
        auto downfn = [](bool verify, const Node& node, size_t index) {
802
            // For WRAP_V, the subexpression is certainly followed by OP_VERIFY.
803
25.0k
            if (node.fragment == Fragment::WRAP_V) return true;
804
            // The subexpression of WRAP_S, and the last subexpression of AND_V
805
            // inherit the followed-by-OP_VERIFY property from the parent.
806
24.7k
            if (node.fragment == Fragment::WRAP_S ||
807
24.7k
                (node.fragment == Fragment::AND_V && index == 1)) return verify;
808
24.5k
            return false;
809
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
801
1.66M
        auto downfn = [](bool verify, const Node& node, size_t index) {
802
            // For WRAP_V, the subexpression is certainly followed by OP_VERIFY.
803
1.66M
            if (node.fragment == Fragment::WRAP_V) return true;
804
            // The subexpression of WRAP_S, and the last subexpression of AND_V
805
            // inherit the followed-by-OP_VERIFY property from the parent.
806
1.65M
            if (node.fragment == Fragment::WRAP_S ||
807
1.65M
                (node.fragment == Fragment::AND_V && index == 1)) return verify;
808
1.65M
            return false;
809
1.65M
        };
810
        // The upward function computes for a node, given its followed-by-OP_VERIFY status
811
        // and the CScripts of its child nodes, the CScript of the node.
812
1.84k
        const bool is_tapscript{IsTapscript(m_script_ctx)};
813
1.68M
        auto upfn = [&ctx, is_tapscript](bool verify, const Node& node, std::span<CScript> subs) -> CScript {
814
1.68M
            switch (node.fragment) {
815
3.63k
                case Fragment::PK_K: return BuildScript(ctx.ToPKBytes(node.keys[0]));
816
590
                case Fragment::PK_H: return BuildScript(OP_DUP, OP_HASH160, ctx.ToPKHBytes(node.keys[0]), OP_EQUALVERIFY);
817
6.53k
                case Fragment::OLDER: return BuildScript(node.k, OP_CHECKSEQUENCEVERIFY);
818
1.13k
                case Fragment::AFTER: return BuildScript(node.k, OP_CHECKLOCKTIMEVERIFY);
819
133
                case Fragment::SHA256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_SHA256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
820
113
                case Fragment::RIPEMD160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_RIPEMD160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
821
162
                case Fragment::HASH256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
822
117
                case Fragment::HASH160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
823
7.82k
                case Fragment::WRAP_A: return BuildScript(OP_TOALTSTACK, subs[0], OP_FROMALTSTACK);
824
1.48k
                case Fragment::WRAP_S: return BuildScript(OP_SWAP, subs[0]);
825
4.16k
                case Fragment::WRAP_C: return BuildScript(std::move(subs[0]), verify ? OP_CHECKSIGVERIFY : OP_CHECKSIG);
826
145
                case Fragment::WRAP_D: return BuildScript(OP_DUP, OP_IF, subs[0], OP_ENDIF);
827
1.28k
                case Fragment::WRAP_V: {
828
1.28k
                    if (node.subs[0].GetType() << "x"_mst) {
829
352
                        return BuildScript(std::move(subs[0]), OP_VERIFY);
830
935
                    } else {
831
935
                        return std::move(subs[0]);
832
935
                    }
833
1.28k
                }
834
24
                case Fragment::WRAP_J: return BuildScript(OP_SIZE, OP_0NOTEQUAL, OP_IF, subs[0], OP_ENDIF);
835
1.64M
                case Fragment::WRAP_N: return BuildScript(std::move(subs[0]), OP_0NOTEQUAL);
836
236
                case Fragment::JUST_1: return BuildScript(OP_1);
837
1.14k
                case Fragment::JUST_0: return BuildScript(OP_0);
838
1.11k
                case Fragment::AND_V: return BuildScript(std::move(subs[0]), subs[1]);
839
7.42k
                case Fragment::AND_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLAND);
840
78
                case Fragment::OR_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLOR);
841
150
                case Fragment::OR_D: return BuildScript(std::move(subs[0]), OP_IFDUP, OP_NOTIF, subs[1], OP_ENDIF);
842
57
                case Fragment::OR_C: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[1], OP_ENDIF);
843
1.05k
                case Fragment::OR_I: return BuildScript(OP_IF, subs[0], OP_ELSE, subs[1], OP_ENDIF);
844
262
                case Fragment::ANDOR: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[2], OP_ELSE, subs[1], OP_ENDIF);
845
212
                case Fragment::MULTI: {
846
212
                    CHECK_NONFATAL(!is_tapscript);
847
212
                    CScript script = BuildScript(node.k);
848
445
                    for (const auto& key : node.keys) {
849
445
                        script = BuildScript(std::move(script), ctx.ToPKBytes(key));
850
445
                    }
851
212
                    return BuildScript(std::move(script), node.keys.size(), verify ? OP_CHECKMULTISIGVERIFY : OP_CHECKMULTISIG);
852
1.28k
                }
853
52
                case Fragment::MULTI_A: {
854
52
                    CHECK_NONFATAL(is_tapscript);
855
52
                    CScript script = BuildScript(ctx.ToPKBytes(*node.keys.begin()), OP_CHECKSIG);
856
197
                    for (auto it = node.keys.begin() + 1; it != node.keys.end(); ++it) {
857
145
                        script = BuildScript(std::move(script), ctx.ToPKBytes(*it), OP_CHECKSIGADD);
858
145
                    }
859
52
                    return BuildScript(std::move(script), node.k, verify ? OP_NUMEQUALVERIFY : OP_NUMEQUAL);
860
1.28k
                }
861
548
                case Fragment::THRESH: {
862
548
                    CScript script = std::move(subs[0]);
863
2.35k
                    for (size_t i = 1; i < subs.size(); ++i) {
864
1.80k
                        script = BuildScript(std::move(script), subs[i], OP_ADD);
865
1.80k
                    }
866
548
                    return BuildScript(std::move(script), node.k, verify ? OP_EQUALVERIFY : OP_EQUAL);
867
1.28k
                }
868
1.68M
            }
869
1.68M
            assert(false);
870
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
813
25.4k
        auto upfn = [&ctx, is_tapscript](bool verify, const Node& node, std::span<CScript> subs) -> CScript {
814
25.4k
            switch (node.fragment) {
815
1.36k
                case Fragment::PK_K: return BuildScript(ctx.ToPKBytes(node.keys[0]));
816
78
                case Fragment::PK_H: return BuildScript(OP_DUP, OP_HASH160, ctx.ToPKHBytes(node.keys[0]), OP_EQUALVERIFY);
817
6.11k
                case Fragment::OLDER: return BuildScript(node.k, OP_CHECKSEQUENCEVERIFY);
818
195
                case Fragment::AFTER: return BuildScript(node.k, OP_CHECKLOCKTIMEVERIFY);
819
63
                case Fragment::SHA256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_SHA256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
820
21
                case Fragment::RIPEMD160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_RIPEMD160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
821
42
                case Fragment::HASH256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
822
18
                case Fragment::HASH160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
823
7.33k
                case Fragment::WRAP_A: return BuildScript(OP_TOALTSTACK, subs[0], OP_FROMALTSTACK);
824
30
                case Fragment::WRAP_S: return BuildScript(OP_SWAP, subs[0]);
825
1.39k
                case Fragment::WRAP_C: return BuildScript(std::move(subs[0]), verify ? OP_CHECKSIGVERIFY : OP_CHECKSIG);
826
15
                case Fragment::WRAP_D: return BuildScript(OP_DUP, OP_IF, subs[0], OP_ENDIF);
827
243
                case Fragment::WRAP_V: {
828
243
                    if (node.subs[0].GetType() << "x"_mst) {
829
192
                        return BuildScript(std::move(subs[0]), OP_VERIFY);
830
192
                    } else {
831
51
                        return std::move(subs[0]);
832
51
                    }
833
243
                }
834
24
                case Fragment::WRAP_J: return BuildScript(OP_SIZE, OP_0NOTEQUAL, OP_IF, subs[0], OP_ENDIF);
835
45
                case Fragment::WRAP_N: return BuildScript(std::move(subs[0]), OP_0NOTEQUAL);
836
231
                case Fragment::JUST_1: return BuildScript(OP_1);
837
249
                case Fragment::JUST_0: return BuildScript(OP_0);
838
198
                case Fragment::AND_V: return BuildScript(std::move(subs[0]), subs[1]);
839
7.25k
                case Fragment::AND_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLAND);
840
24
                case Fragment::OR_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLOR);
841
45
                case Fragment::OR_D: return BuildScript(std::move(subs[0]), OP_IFDUP, OP_NOTIF, subs[1], OP_ENDIF);
842
18
                case Fragment::OR_C: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[1], OP_ENDIF);
843
237
                case Fragment::OR_I: return BuildScript(OP_IF, subs[0], OP_ELSE, subs[1], OP_ENDIF);
844
87
                case Fragment::ANDOR: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[2], OP_ELSE, subs[1], OP_ENDIF);
845
36
                case Fragment::MULTI: {
846
36
                    CHECK_NONFATAL(!is_tapscript);
847
36
                    CScript script = BuildScript(node.k);
848
69
                    for (const auto& key : node.keys) {
849
69
                        script = BuildScript(std::move(script), ctx.ToPKBytes(key));
850
69
                    }
851
36
                    return BuildScript(std::move(script), node.keys.size(), verify ? OP_CHECKMULTISIGVERIFY : OP_CHECKMULTISIG);
852
243
                }
853
6
                case Fragment::MULTI_A: {
854
6
                    CHECK_NONFATAL(is_tapscript);
855
6
                    CScript script = BuildScript(ctx.ToPKBytes(*node.keys.begin()), OP_CHECKSIG);
856
69
                    for (auto it = node.keys.begin() + 1; it != node.keys.end(); ++it) {
857
63
                        script = BuildScript(std::move(script), ctx.ToPKBytes(*it), OP_CHECKSIGADD);
858
63
                    }
859
6
                    return BuildScript(std::move(script), node.k, verify ? OP_NUMEQUALVERIFY : OP_NUMEQUAL);
860
243
                }
861
48
                case Fragment::THRESH: {
862
48
                    CScript script = std::move(subs[0]);
863
138
                    for (size_t i = 1; i < subs.size(); ++i) {
864
90
                        script = BuildScript(std::move(script), subs[i], OP_ADD);
865
90
                    }
866
48
                    return BuildScript(std::move(script), node.k, verify ? OP_EQUALVERIFY : OP_EQUAL);
867
243
                }
868
25.4k
            }
869
25.4k
            assert(false);
870
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
813
1.66M
        auto upfn = [&ctx, is_tapscript](bool verify, const Node& node, std::span<CScript> subs) -> CScript {
814
1.66M
            switch (node.fragment) {
815
2.26k
                case Fragment::PK_K: return BuildScript(ctx.ToPKBytes(node.keys[0]));
816
512
                case Fragment::PK_H: return BuildScript(OP_DUP, OP_HASH160, ctx.ToPKHBytes(node.keys[0]), OP_EQUALVERIFY);
817
424
                case Fragment::OLDER: return BuildScript(node.k, OP_CHECKSEQUENCEVERIFY);
818
935
                case Fragment::AFTER: return BuildScript(node.k, OP_CHECKLOCKTIMEVERIFY);
819
70
                case Fragment::SHA256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_SHA256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
820
92
                case Fragment::RIPEMD160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_RIPEMD160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
821
120
                case Fragment::HASH256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
822
99
                case Fragment::HASH160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
823
485
                case Fragment::WRAP_A: return BuildScript(OP_TOALTSTACK, subs[0], OP_FROMALTSTACK);
824
1.45k
                case Fragment::WRAP_S: return BuildScript(OP_SWAP, subs[0]);
825
2.77k
                case Fragment::WRAP_C: return BuildScript(std::move(subs[0]), verify ? OP_CHECKSIGVERIFY : OP_CHECKSIG);
826
130
                case Fragment::WRAP_D: return BuildScript(OP_DUP, OP_IF, subs[0], OP_ENDIF);
827
1.04k
                case Fragment::WRAP_V: {
828
1.04k
                    if (node.subs[0].GetType() << "x"_mst) {
829
160
                        return BuildScript(std::move(subs[0]), OP_VERIFY);
830
884
                    } else {
831
884
                        return std::move(subs[0]);
832
884
                    }
833
1.04k
                }
834
0
                case Fragment::WRAP_J: return BuildScript(OP_SIZE, OP_0NOTEQUAL, OP_IF, subs[0], OP_ENDIF);
835
1.64M
                case Fragment::WRAP_N: return BuildScript(std::move(subs[0]), OP_0NOTEQUAL);
836
5
                case Fragment::JUST_1: return BuildScript(OP_1);
837
893
                case Fragment::JUST_0: return BuildScript(OP_0);
838
914
                case Fragment::AND_V: return BuildScript(std::move(subs[0]), subs[1]);
839
172
                case Fragment::AND_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLAND);
840
54
                case Fragment::OR_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLOR);
841
105
                case Fragment::OR_D: return BuildScript(std::move(subs[0]), OP_IFDUP, OP_NOTIF, subs[1], OP_ENDIF);
842
39
                case Fragment::OR_C: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[1], OP_ENDIF);
843
816
                case Fragment::OR_I: return BuildScript(OP_IF, subs[0], OP_ELSE, subs[1], OP_ENDIF);
844
175
                case Fragment::ANDOR: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[2], OP_ELSE, subs[1], OP_ENDIF);
845
176
                case Fragment::MULTI: {
846
176
                    CHECK_NONFATAL(!is_tapscript);
847
176
                    CScript script = BuildScript(node.k);
848
376
                    for (const auto& key : node.keys) {
849
376
                        script = BuildScript(std::move(script), ctx.ToPKBytes(key));
850
376
                    }
851
176
                    return BuildScript(std::move(script), node.keys.size(), verify ? OP_CHECKMULTISIGVERIFY : OP_CHECKMULTISIG);
852
1.04k
                }
853
46
                case Fragment::MULTI_A: {
854
46
                    CHECK_NONFATAL(is_tapscript);
855
46
                    CScript script = BuildScript(ctx.ToPKBytes(*node.keys.begin()), OP_CHECKSIG);
856
128
                    for (auto it = node.keys.begin() + 1; it != node.keys.end(); ++it) {
857
82
                        script = BuildScript(std::move(script), ctx.ToPKBytes(*it), OP_CHECKSIGADD);
858
82
                    }
859
46
                    return BuildScript(std::move(script), node.k, verify ? OP_NUMEQUALVERIFY : OP_NUMEQUAL);
860
1.04k
                }
861
500
                case Fragment::THRESH: {
862
500
                    CScript script = std::move(subs[0]);
863
2.21k
                    for (size_t i = 1; i < subs.size(); ++i) {
864
1.71k
                        script = BuildScript(std::move(script), subs[i], OP_ADD);
865
1.71k
                    }
866
500
                    return BuildScript(std::move(script), node.k, verify ? OP_EQUALVERIFY : OP_EQUAL);
867
1.04k
                }
868
1.66M
            }
869
1.66M
            assert(false);
870
0
        };
871
1.84k
        return TreeEval<CScript>(false, downfn, upfn);
872
1.84k
    }
miniscript_tests.cpp:CScript miniscript::Node<CPubKey>::ToScript<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const
Line
Count
Source
797
375
    {
798
        // To construct the CScript for a Miniscript object, we use the TreeEval algorithm.
799
        // The State is a boolean: whether or not the node's script expansion is followed
800
        // by an OP_VERIFY (which may need to be combined with the last script opcode).
801
375
        auto downfn = [](bool verify, const Node& node, size_t index) {
802
            // For WRAP_V, the subexpression is certainly followed by OP_VERIFY.
803
375
            if (node.fragment == Fragment::WRAP_V) return true;
804
            // The subexpression of WRAP_S, and the last subexpression of AND_V
805
            // inherit the followed-by-OP_VERIFY property from the parent.
806
375
            if (node.fragment == Fragment::WRAP_S ||
807
375
                (node.fragment == Fragment::AND_V && index == 1)) return verify;
808
375
            return false;
809
375
        };
810
        // The upward function computes for a node, given its followed-by-OP_VERIFY status
811
        // and the CScripts of its child nodes, the CScript of the node.
812
375
        const bool is_tapscript{IsTapscript(m_script_ctx)};
813
375
        auto upfn = [&ctx, is_tapscript](bool verify, const Node& node, std::span<CScript> subs) -> CScript {
814
375
            switch (node.fragment) {
815
375
                case Fragment::PK_K: return BuildScript(ctx.ToPKBytes(node.keys[0]));
816
375
                case Fragment::PK_H: return BuildScript(OP_DUP, OP_HASH160, ctx.ToPKHBytes(node.keys[0]), OP_EQUALVERIFY);
817
375
                case Fragment::OLDER: return BuildScript(node.k, OP_CHECKSEQUENCEVERIFY);
818
375
                case Fragment::AFTER: return BuildScript(node.k, OP_CHECKLOCKTIMEVERIFY);
819
375
                case Fragment::SHA256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_SHA256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
820
375
                case Fragment::RIPEMD160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_RIPEMD160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
821
375
                case Fragment::HASH256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
822
375
                case Fragment::HASH160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
823
375
                case Fragment::WRAP_A: return BuildScript(OP_TOALTSTACK, subs[0], OP_FROMALTSTACK);
824
375
                case Fragment::WRAP_S: return BuildScript(OP_SWAP, subs[0]);
825
375
                case Fragment::WRAP_C: return BuildScript(std::move(subs[0]), verify ? OP_CHECKSIGVERIFY : OP_CHECKSIG);
826
375
                case Fragment::WRAP_D: return BuildScript(OP_DUP, OP_IF, subs[0], OP_ENDIF);
827
375
                case Fragment::WRAP_V: {
828
375
                    if (node.subs[0].GetType() << "x"_mst) {
829
375
                        return BuildScript(std::move(subs[0]), OP_VERIFY);
830
375
                    } else {
831
375
                        return std::move(subs[0]);
832
375
                    }
833
375
                }
834
375
                case Fragment::WRAP_J: return BuildScript(OP_SIZE, OP_0NOTEQUAL, OP_IF, subs[0], OP_ENDIF);
835
375
                case Fragment::WRAP_N: return BuildScript(std::move(subs[0]), OP_0NOTEQUAL);
836
375
                case Fragment::JUST_1: return BuildScript(OP_1);
837
375
                case Fragment::JUST_0: return BuildScript(OP_0);
838
375
                case Fragment::AND_V: return BuildScript(std::move(subs[0]), subs[1]);
839
375
                case Fragment::AND_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLAND);
840
375
                case Fragment::OR_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLOR);
841
375
                case Fragment::OR_D: return BuildScript(std::move(subs[0]), OP_IFDUP, OP_NOTIF, subs[1], OP_ENDIF);
842
375
                case Fragment::OR_C: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[1], OP_ENDIF);
843
375
                case Fragment::OR_I: return BuildScript(OP_IF, subs[0], OP_ELSE, subs[1], OP_ENDIF);
844
375
                case Fragment::ANDOR: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[2], OP_ELSE, subs[1], OP_ENDIF);
845
375
                case Fragment::MULTI: {
846
375
                    CHECK_NONFATAL(!is_tapscript);
847
375
                    CScript script = BuildScript(node.k);
848
375
                    for (const auto& key : node.keys) {
849
375
                        script = BuildScript(std::move(script), ctx.ToPKBytes(key));
850
375
                    }
851
375
                    return BuildScript(std::move(script), node.keys.size(), verify ? OP_CHECKMULTISIGVERIFY : OP_CHECKMULTISIG);
852
375
                }
853
375
                case Fragment::MULTI_A: {
854
375
                    CHECK_NONFATAL(is_tapscript);
855
375
                    CScript script = BuildScript(ctx.ToPKBytes(*node.keys.begin()), OP_CHECKSIG);
856
375
                    for (auto it = node.keys.begin() + 1; it != node.keys.end(); ++it) {
857
375
                        script = BuildScript(std::move(script), ctx.ToPKBytes(*it), OP_CHECKSIGADD);
858
375
                    }
859
375
                    return BuildScript(std::move(script), node.k, verify ? OP_NUMEQUALVERIFY : OP_NUMEQUAL);
860
375
                }
861
375
                case Fragment::THRESH: {
862
375
                    CScript script = std::move(subs[0]);
863
375
                    for (size_t i = 1; i < subs.size(); ++i) {
864
375
                        script = BuildScript(std::move(script), subs[i], OP_ADD);
865
375
                    }
866
375
                    return BuildScript(std::move(script), node.k, verify ? OP_EQUALVERIFY : OP_EQUAL);
867
375
                }
868
375
            }
869
375
            assert(false);
870
375
        };
871
375
        return TreeEval<CScript>(false, downfn, upfn);
872
375
    }
descriptor.cpp:CScript miniscript::Node<unsigned int>::ToScript<(anonymous namespace)::ScriptMaker>((anonymous namespace)::ScriptMaker const&) const
Line
Count
Source
797
1.47k
    {
798
        // To construct the CScript for a Miniscript object, we use the TreeEval algorithm.
799
        // The State is a boolean: whether or not the node's script expansion is followed
800
        // by an OP_VERIFY (which may need to be combined with the last script opcode).
801
1.47k
        auto downfn = [](bool verify, const Node& node, size_t index) {
802
            // For WRAP_V, the subexpression is certainly followed by OP_VERIFY.
803
1.47k
            if (node.fragment == Fragment::WRAP_V) return true;
804
            // The subexpression of WRAP_S, and the last subexpression of AND_V
805
            // inherit the followed-by-OP_VERIFY property from the parent.
806
1.47k
            if (node.fragment == Fragment::WRAP_S ||
807
1.47k
                (node.fragment == Fragment::AND_V && index == 1)) return verify;
808
1.47k
            return false;
809
1.47k
        };
810
        // The upward function computes for a node, given its followed-by-OP_VERIFY status
811
        // and the CScripts of its child nodes, the CScript of the node.
812
1.47k
        const bool is_tapscript{IsTapscript(m_script_ctx)};
813
1.47k
        auto upfn = [&ctx, is_tapscript](bool verify, const Node& node, std::span<CScript> subs) -> CScript {
814
1.47k
            switch (node.fragment) {
815
1.47k
                case Fragment::PK_K: return BuildScript(ctx.ToPKBytes(node.keys[0]));
816
1.47k
                case Fragment::PK_H: return BuildScript(OP_DUP, OP_HASH160, ctx.ToPKHBytes(node.keys[0]), OP_EQUALVERIFY);
817
1.47k
                case Fragment::OLDER: return BuildScript(node.k, OP_CHECKSEQUENCEVERIFY);
818
1.47k
                case Fragment::AFTER: return BuildScript(node.k, OP_CHECKLOCKTIMEVERIFY);
819
1.47k
                case Fragment::SHA256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_SHA256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
820
1.47k
                case Fragment::RIPEMD160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_RIPEMD160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
821
1.47k
                case Fragment::HASH256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
822
1.47k
                case Fragment::HASH160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL);
823
1.47k
                case Fragment::WRAP_A: return BuildScript(OP_TOALTSTACK, subs[0], OP_FROMALTSTACK);
824
1.47k
                case Fragment::WRAP_S: return BuildScript(OP_SWAP, subs[0]);
825
1.47k
                case Fragment::WRAP_C: return BuildScript(std::move(subs[0]), verify ? OP_CHECKSIGVERIFY : OP_CHECKSIG);
826
1.47k
                case Fragment::WRAP_D: return BuildScript(OP_DUP, OP_IF, subs[0], OP_ENDIF);
827
1.47k
                case Fragment::WRAP_V: {
828
1.47k
                    if (node.subs[0].GetType() << "x"_mst) {
829
1.47k
                        return BuildScript(std::move(subs[0]), OP_VERIFY);
830
1.47k
                    } else {
831
1.47k
                        return std::move(subs[0]);
832
1.47k
                    }
833
1.47k
                }
834
1.47k
                case Fragment::WRAP_J: return BuildScript(OP_SIZE, OP_0NOTEQUAL, OP_IF, subs[0], OP_ENDIF);
835
1.47k
                case Fragment::WRAP_N: return BuildScript(std::move(subs[0]), OP_0NOTEQUAL);
836
1.47k
                case Fragment::JUST_1: return BuildScript(OP_1);
837
1.47k
                case Fragment::JUST_0: return BuildScript(OP_0);
838
1.47k
                case Fragment::AND_V: return BuildScript(std::move(subs[0]), subs[1]);
839
1.47k
                case Fragment::AND_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLAND);
840
1.47k
                case Fragment::OR_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLOR);
841
1.47k
                case Fragment::OR_D: return BuildScript(std::move(subs[0]), OP_IFDUP, OP_NOTIF, subs[1], OP_ENDIF);
842
1.47k
                case Fragment::OR_C: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[1], OP_ENDIF);
843
1.47k
                case Fragment::OR_I: return BuildScript(OP_IF, subs[0], OP_ELSE, subs[1], OP_ENDIF);
844
1.47k
                case Fragment::ANDOR: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[2], OP_ELSE, subs[1], OP_ENDIF);
845
1.47k
                case Fragment::MULTI: {
846
1.47k
                    CHECK_NONFATAL(!is_tapscript);
847
1.47k
                    CScript script = BuildScript(node.k);
848
1.47k
                    for (const auto& key : node.keys) {
849
1.47k
                        script = BuildScript(std::move(script), ctx.ToPKBytes(key));
850
1.47k
                    }
851
1.47k
                    return BuildScript(std::move(script), node.keys.size(), verify ? OP_CHECKMULTISIGVERIFY : OP_CHECKMULTISIG);
852
1.47k
                }
853
1.47k
                case Fragment::MULTI_A: {
854
1.47k
                    CHECK_NONFATAL(is_tapscript);
855
1.47k
                    CScript script = BuildScript(ctx.ToPKBytes(*node.keys.begin()), OP_CHECKSIG);
856
1.47k
                    for (auto it = node.keys.begin() + 1; it != node.keys.end(); ++it) {
857
1.47k
                        script = BuildScript(std::move(script), ctx.ToPKBytes(*it), OP_CHECKSIGADD);
858
1.47k
                    }
859
1.47k
                    return BuildScript(std::move(script), node.k, verify ? OP_NUMEQUALVERIFY : OP_NUMEQUAL);
860
1.47k
                }
861
1.47k
                case Fragment::THRESH: {
862
1.47k
                    CScript script = std::move(subs[0]);
863
1.47k
                    for (size_t i = 1; i < subs.size(); ++i) {
864
1.47k
                        script = BuildScript(std::move(script), subs[i], OP_ADD);
865
1.47k
                    }
866
1.47k
                    return BuildScript(std::move(script), node.k, verify ? OP_EQUALVERIFY : OP_EQUAL);
867
1.47k
                }
868
1.47k
            }
869
1.47k
            assert(false);
870
1.47k
        };
871
1.47k
        return TreeEval<CScript>(false, downfn, upfn);
872
1.47k
    }
873
874
    template<typename CTx>
875
15
    std::optional<std::string> ToString(const CTx& ctx) const {
876
15
        bool dummy{false};
877
15
        return ToString(ctx, dummy);
878
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
875
1
    std::optional<std::string> ToString(const CTx& ctx) const {
876
1
        bool dummy{false};
877
1
        return ToString(ctx, dummy);
878
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
875
14
    std::optional<std::string> ToString(const CTx& ctx) const {
876
14
        bool dummy{false};
877
14
        return ToString(ctx, dummy);
878
14
    }
879
880
    template<typename CTx>
881
1.10k
    std::optional<std::string> ToString(const CTx& ctx, bool& has_priv_key) const {
882
        // To construct the std::string representation for a Miniscript object, we use
883
        // the TreeEvalMaybe algorithm. The State is a boolean: whether the parent node is a
884
        // wrapper. If so, non-wrapper expressions must be prefixed with a ":".
885
2.97M
        auto downfn = [](bool, const Node& node, size_t) {
886
2.97M
            return (node.fragment == Fragment::WRAP_A || node.fragment == Fragment::WRAP_S ||
887
2.97M
                    node.fragment == Fragment::WRAP_D || node.fragment == Fragment::WRAP_V ||
888
2.97M
                    node.fragment == Fragment::WRAP_J || node.fragment == Fragment::WRAP_N ||
889
2.97M
                    node.fragment == Fragment::WRAP_C ||
890
2.97M
                    (node.fragment == Fragment::AND_V && node.subs[1].fragment == Fragment::JUST_1) ||
891
2.97M
                    (node.fragment == Fragment::OR_I && node.subs[0].fragment == Fragment::JUST_0) ||
892
2.97M
                    (node.fragment == Fragment::OR_I && node.subs[1].fragment == Fragment::JUST_0));
893
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
885
3
        auto downfn = [](bool, const Node& node, size_t) {
886
3
            return (node.fragment == Fragment::WRAP_A || node.fragment == Fragment::WRAP_S ||
887
3
                    node.fragment == Fragment::WRAP_D || node.fragment == Fragment::WRAP_V ||
888
3
                    node.fragment == Fragment::WRAP_J || node.fragment == Fragment::WRAP_N ||
889
3
                    node.fragment == Fragment::WRAP_C ||
890
3
                    (node.fragment == Fragment::AND_V && node.subs[1].fragment == Fragment::JUST_1) ||
891
3
                    (node.fragment == Fragment::OR_I && node.subs[0].fragment == Fragment::JUST_0) ||
892
3
                    (node.fragment == Fragment::OR_I && node.subs[1].fragment == Fragment::JUST_0));
893
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
885
65
        auto downfn = [](bool, const Node& node, size_t) {
886
65
            return (node.fragment == Fragment::WRAP_A || node.fragment == Fragment::WRAP_S ||
887
65
                    node.fragment == Fragment::WRAP_D || node.fragment == Fragment::WRAP_V ||
888
65
                    node.fragment == Fragment::WRAP_J || node.fragment == Fragment::WRAP_N ||
889
65
                    node.fragment == Fragment::WRAP_C ||
890
65
                    (node.fragment == Fragment::AND_V && node.subs[1].fragment == Fragment::JUST_1) ||
891
65
                    (node.fragment == Fragment::OR_I && node.subs[0].fragment == Fragment::JUST_0) ||
892
65
                    (node.fragment == Fragment::OR_I && node.subs[1].fragment == Fragment::JUST_0));
893
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
885
2.97M
        auto downfn = [](bool, const Node& node, size_t) {
886
2.97M
            return (node.fragment == Fragment::WRAP_A || node.fragment == Fragment::WRAP_S ||
887
2.97M
                    node.fragment == Fragment::WRAP_D || node.fragment == Fragment::WRAP_V ||
888
2.97M
                    node.fragment == Fragment::WRAP_J || node.fragment == Fragment::WRAP_N ||
889
2.97M
                    node.fragment == Fragment::WRAP_C ||
890
2.97M
                    (node.fragment == Fragment::AND_V && node.subs[1].fragment == Fragment::JUST_1) ||
891
2.97M
                    (node.fragment == Fragment::OR_I && node.subs[0].fragment == Fragment::JUST_0) ||
892
2.97M
                    (node.fragment == Fragment::OR_I && node.subs[1].fragment == Fragment::JUST_0));
893
2.97M
        };
894
5.15k
        auto toString = [&ctx, &has_priv_key](Key key) -> std::optional<std::string> {
895
5.15k
            bool fragment_has_priv_key{false};
896
5.15k
            auto key_str{ctx.ToString(key, fragment_has_priv_key)};
897
5.15k
            if (key_str) has_priv_key = has_priv_key || fragment_has_priv_key;
898
5.15k
            return key_str;
899
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
894
30
        auto toString = [&ctx, &has_priv_key](Key key) -> std::optional<std::string> {
895
30
            bool fragment_has_priv_key{false};
896
30
            auto key_str{ctx.ToString(key, fragment_has_priv_key)};
897
30
            if (key_str) has_priv_key = has_priv_key || fragment_has_priv_key;
898
30
            return key_str;
899
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
894
5.12k
        auto toString = [&ctx, &has_priv_key](Key key) -> std::optional<std::string> {
895
5.12k
            bool fragment_has_priv_key{false};
896
5.12k
            auto key_str{ctx.ToString(key, fragment_has_priv_key)};
897
5.12k
            if (key_str) has_priv_key = has_priv_key || fragment_has_priv_key;
898
5.12k
            return key_str;
899
5.12k
        };
900
        // The upward function computes for a node, given whether its parent is a wrapper,
901
        // and the string representations of its child nodes, the string representation of the node.
902
1.10k
        const bool is_tapscript{IsTapscript(m_script_ctx)};
903
2.97M
        auto upfn = [is_tapscript, &toString](bool wrapped, const Node& node, std::span<std::string> subs) -> std::optional<std::string> {
904
2.97M
            std::string ret = wrapped ? ":" : "";
905
906
2.97M
            switch (node.fragment) {
907
609
                case Fragment::WRAP_A: return "a" + std::move(subs[0]);
908
338
                case Fragment::WRAP_S: return "s" + std::move(subs[0]);
909
2.38k
                case Fragment::WRAP_C:
910
2.38k
                    if (node.subs[0].fragment == Fragment::PK_K) {
911
                        // pk(K) is syntactic sugar for c:pk_k(K)
912
1.74k
                        auto key_str = toString(node.subs[0].keys[0]);
913
1.74k
                        if (!key_str) return {};
914
1.74k
                        return std::move(ret) + "pk(" + std::move(*key_str) + ")";
915
1.74k
                    }
916
647
                    if (node.subs[0].fragment == Fragment::PK_H) {
917
                        // pkh(K) is syntactic sugar for c:pk_h(K)
918
625
                        auto key_str = toString(node.subs[0].keys[0]);
919
625
                        if (!key_str) return {};
920
625
                        return std::move(ret) + "pkh(" + std::move(*key_str) + ")";
921
625
                    }
922
22
                    return "c" + std::move(subs[0]);
923
84
                case Fragment::WRAP_D: return "d" + std::move(subs[0]);
924
1.08k
                case Fragment::WRAP_V: return "v" + std::move(subs[0]);
925
0
                case Fragment::WRAP_J: return "j" + std::move(subs[0]);
926
2.96M
                case Fragment::WRAP_N: return "n" + std::move(subs[0]);
927
997
                case Fragment::AND_V:
928
                    // t:X is syntactic sugar for and_v(X,1).
929
997
                    if (node.subs[1].fragment == Fragment::JUST_1) return "t" + std::move(subs[0]);
930
991
                    break;
931
991
                case Fragment::OR_I:
932
229
                    if (node.subs[0].fragment == Fragment::JUST_0) return "l" + std::move(subs[1]);
933
108
                    if (node.subs[1].fragment == Fragment::JUST_0) return "u" + std::move(subs[0]);
934
108
                    break;
935
4.70k
                default: break;
936
2.97M
            }
937
5.80k
            switch (node.fragment) {
938
1.78k
                case Fragment::PK_K: {
939
1.78k
                    auto key_str = toString(node.keys[0]);
940
1.78k
                    if (!key_str) return {};
941
1.78k
                    return std::move(ret) + "pk_k(" + std::move(*key_str) + ")";
942
1.78k
                }
943
625
                case Fragment::PK_H: {
944
625
                    auto key_str = toString(node.keys[0]);
945
625
                    if (!key_str) return {};
946
625
                    return std::move(ret) + "pk_h(" + std::move(*key_str) + ")";
947
625
                }
948
436
                case Fragment::AFTER: return std::move(ret) + "after(" + util::ToString(node.k) + ")";
949
400
                case Fragment::OLDER: return std::move(ret) + "older(" + util::ToString(node.k) + ")";
950
30
                case Fragment::HASH256: return std::move(ret) + "hash256(" + HexStr(node.data) + ")";
951
63
                case Fragment::HASH160: return std::move(ret) + "hash160(" + HexStr(node.data) + ")";
952
71
                case Fragment::SHA256: return std::move(ret) + "sha256(" + HexStr(node.data) + ")";
953
35
                case Fragment::RIPEMD160: return std::move(ret) + "ripemd160(" + HexStr(node.data) + ")";
954
7
                case Fragment::JUST_1: return std::move(ret) + "1";
955
162
                case Fragment::JUST_0: return std::move(ret) + "0";
956
991
                case Fragment::AND_V: return std::move(ret) + "and_v(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
957
368
                case Fragment::AND_B: return std::move(ret) + "and_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
958
62
                case Fragment::OR_B: return std::move(ret) + "or_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
959
77
                case Fragment::OR_D: return std::move(ret) + "or_d(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
960
42
                case Fragment::OR_C: return std::move(ret) + "or_c(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
961
108
                case Fragment::OR_I: return std::move(ret) + "or_i(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
962
182
                case Fragment::ANDOR:
963
                    // and_n(X,Y) is syntactic sugar for andor(X,Y,0).
964
182
                    if (node.subs[2].fragment == Fragment::JUST_0) return std::move(ret) + "and_n(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
965
142
                    return std::move(ret) + "andor(" + std::move(subs[0]) + "," + std::move(subs[1]) + "," + std::move(subs[2]) + ")";
966
96
                case Fragment::MULTI: {
967
96
                    CHECK_NONFATAL(!is_tapscript);
968
96
                    auto str = std::move(ret) + "multi(" + util::ToString(node.k);
969
246
                    for (const auto& key : node.keys) {
970
246
                        auto key_str = toString(key);
971
246
                        if (!key_str) return {};
972
246
                        str += "," + std::move(*key_str);
973
246
                    }
974
96
                    return std::move(str) + ")";
975
96
                }
976
51
                case Fragment::MULTI_A: {
977
51
                    CHECK_NONFATAL(is_tapscript);
978
51
                    auto str = std::move(ret) + "multi_a(" + util::ToString(node.k);
979
130
                    for (const auto& key : node.keys) {
980
130
                        auto key_str = toString(key);
981
130
                        if (!key_str) return {};
982
130
                        str += "," + std::move(*key_str);
983
130
                    }
984
51
                    return std::move(str) + ")";
985
51
                }
986
211
                case Fragment::THRESH: {
987
211
                    auto str = std::move(ret) + "thresh(" + util::ToString(node.k);
988
730
                    for (auto& sub : subs) {
989
730
                        str += "," + std::move(sub);
990
730
                    }
991
211
                    return std::move(str) + ")";
992
51
                }
993
0
                default: break;
994
5.80k
            }
995
5.80k
            assert(false);
996
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
903
4
        auto upfn = [is_tapscript, &toString](bool wrapped, const Node& node, std::span<std::string> subs) -> std::optional<std::string> {
904
4
            std::string ret = wrapped ? ":" : "";
905
906
4
            switch (node.fragment) {
907
1
                case Fragment::WRAP_A: return "a" + std::move(subs[0]);
908
0
                case Fragment::WRAP_S: return "s" + std::move(subs[0]);
909
0
                case Fragment::WRAP_C:
910
0
                    if (node.subs[0].fragment == Fragment::PK_K) {
911
                        // pk(K) is syntactic sugar for c:pk_k(K)
912
0
                        auto key_str = toString(node.subs[0].keys[0]);
913
0
                        if (!key_str) return {};
914
0
                        return std::move(ret) + "pk(" + std::move(*key_str) + ")";
915
0
                    }
916
0
                    if (node.subs[0].fragment == Fragment::PK_H) {
917
                        // pkh(K) is syntactic sugar for c:pk_h(K)
918
0
                        auto key_str = toString(node.subs[0].keys[0]);
919
0
                        if (!key_str) return {};
920
0
                        return std::move(ret) + "pkh(" + std::move(*key_str) + ")";
921
0
                    }
922
0
                    return "c" + std::move(subs[0]);
923
0
                case Fragment::WRAP_D: return "d" + std::move(subs[0]);
924
0
                case Fragment::WRAP_V: return "v" + std::move(subs[0]);
925
0
                case Fragment::WRAP_J: return "j" + std::move(subs[0]);
926
0
                case Fragment::WRAP_N: return "n" + std::move(subs[0]);
927
0
                case Fragment::AND_V:
928
                    // t:X is syntactic sugar for and_v(X,1).
929
0
                    if (node.subs[1].fragment == Fragment::JUST_1) return "t" + std::move(subs[0]);
930
0
                    break;
931
0
                case Fragment::OR_I:
932
0
                    if (node.subs[0].fragment == Fragment::JUST_0) return "l" + std::move(subs[1]);
933
0
                    if (node.subs[1].fragment == Fragment::JUST_0) return "u" + std::move(subs[0]);
934
0
                    break;
935
3
                default: break;
936
4
            }
937
3
            switch (node.fragment) {
938
0
                case Fragment::PK_K: {
939
0
                    auto key_str = toString(node.keys[0]);
940
0
                    if (!key_str) return {};
941
0
                    return std::move(ret) + "pk_k(" + std::move(*key_str) + ")";
942
0
                }
943
0
                case Fragment::PK_H: {
944
0
                    auto key_str = toString(node.keys[0]);
945
0
                    if (!key_str) return {};
946
0
                    return std::move(ret) + "pk_h(" + std::move(*key_str) + ")";
947
0
                }
948
2
                case Fragment::AFTER: return std::move(ret) + "after(" + util::ToString(node.k) + ")";
949
0
                case Fragment::OLDER: return std::move(ret) + "older(" + util::ToString(node.k) + ")";
950
0
                case Fragment::HASH256: return std::move(ret) + "hash256(" + HexStr(node.data) + ")";
951
0
                case Fragment::HASH160: return std::move(ret) + "hash160(" + HexStr(node.data) + ")";
952
0
                case Fragment::SHA256: return std::move(ret) + "sha256(" + HexStr(node.data) + ")";
953
0
                case Fragment::RIPEMD160: return std::move(ret) + "ripemd160(" + HexStr(node.data) + ")";
954
0
                case Fragment::JUST_1: return std::move(ret) + "1";
955
0
                case Fragment::JUST_0: return std::move(ret) + "0";
956
0
                case Fragment::AND_V: return std::move(ret) + "and_v(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
957
1
                case Fragment::AND_B: return std::move(ret) + "and_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
958
0
                case Fragment::OR_B: return std::move(ret) + "or_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
959
0
                case Fragment::OR_D: return std::move(ret) + "or_d(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
960
0
                case Fragment::OR_C: return std::move(ret) + "or_c(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
961
0
                case Fragment::OR_I: return std::move(ret) + "or_i(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
962
0
                case Fragment::ANDOR:
963
                    // and_n(X,Y) is syntactic sugar for andor(X,Y,0).
964
0
                    if (node.subs[2].fragment == Fragment::JUST_0) return std::move(ret) + "and_n(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
965
0
                    return std::move(ret) + "andor(" + std::move(subs[0]) + "," + std::move(subs[1]) + "," + std::move(subs[2]) + ")";
966
0
                case Fragment::MULTI: {
967
0
                    CHECK_NONFATAL(!is_tapscript);
968
0
                    auto str = std::move(ret) + "multi(" + util::ToString(node.k);
969
0
                    for (const auto& key : node.keys) {
970
0
                        auto key_str = toString(key);
971
0
                        if (!key_str) return {};
972
0
                        str += "," + std::move(*key_str);
973
0
                    }
974
0
                    return std::move(str) + ")";
975
0
                }
976
0
                case Fragment::MULTI_A: {
977
0
                    CHECK_NONFATAL(is_tapscript);
978
0
                    auto str = std::move(ret) + "multi_a(" + util::ToString(node.k);
979
0
                    for (const auto& key : node.keys) {
980
0
                        auto key_str = toString(key);
981
0
                        if (!key_str) return {};
982
0
                        str += "," + std::move(*key_str);
983
0
                    }
984
0
                    return std::move(str) + ")";
985
0
                }
986
0
                case Fragment::THRESH: {
987
0
                    auto str = std::move(ret) + "thresh(" + util::ToString(node.k);
988
0
                    for (auto& sub : subs) {
989
0
                        str += "," + std::move(sub);
990
0
                    }
991
0
                    return std::move(str) + ")";
992
0
                }
993
0
                default: break;
994
3
            }
995
3
            assert(false);
996
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
903
79
        auto upfn = [is_tapscript, &toString](bool wrapped, const Node& node, std::span<std::string> subs) -> std::optional<std::string> {
904
79
            std::string ret = wrapped ? ":" : "";
905
906
79
            switch (node.fragment) {
907
3
                case Fragment::WRAP_A: return "a" + std::move(subs[0]);
908
6
                case Fragment::WRAP_S: return "s" + std::move(subs[0]);
909
14
                case Fragment::WRAP_C:
910
14
                    if (node.subs[0].fragment == Fragment::PK_K) {
911
                        // pk(K) is syntactic sugar for c:pk_k(K)
912
10
                        auto key_str = toString(node.subs[0].keys[0]);
913
10
                        if (!key_str) return {};
914
10
                        return std::move(ret) + "pk(" + std::move(*key_str) + ")";
915
10
                    }
916
4
                    if (node.subs[0].fragment == Fragment::PK_H) {
917
                        // pkh(K) is syntactic sugar for c:pk_h(K)
918
2
                        auto key_str = toString(node.subs[0].keys[0]);
919
2
                        if (!key_str) return {};
920
2
                        return std::move(ret) + "pkh(" + std::move(*key_str) + ")";
921
2
                    }
922
2
                    return "c" + std::move(subs[0]);
923
0
                case Fragment::WRAP_D: return "d" + std::move(subs[0]);
924
6
                case Fragment::WRAP_V: return "v" + std::move(subs[0]);
925
0
                case Fragment::WRAP_J: return "j" + std::move(subs[0]);
926
0
                case Fragment::WRAP_N: return "n" + std::move(subs[0]);
927
2
                case Fragment::AND_V:
928
                    // t:X is syntactic sugar for and_v(X,1).
929
2
                    if (node.subs[1].fragment == Fragment::JUST_1) return "t" + std::move(subs[0]);
930
2
                    break;
931
2
                case Fragment::OR_I:
932
2
                    if (node.subs[0].fragment == Fragment::JUST_0) return "l" + std::move(subs[1]);
933
2
                    if (node.subs[1].fragment == Fragment::JUST_0) return "u" + std::move(subs[0]);
934
2
                    break;
935
46
                default: break;
936
79
            }
937
50
            switch (node.fragment) {
938
16
                case Fragment::PK_K: {
939
16
                    auto key_str = toString(node.keys[0]);
940
16
                    if (!key_str) return {};
941
16
                    return std::move(ret) + "pk_k(" + std::move(*key_str) + ")";
942
16
                }
943
2
                case Fragment::PK_H: {
944
2
                    auto key_str = toString(node.keys[0]);
945
2
                    if (!key_str) return {};
946
2
                    return std::move(ret) + "pk_h(" + std::move(*key_str) + ")";
947
2
                }
948
2
                case Fragment::AFTER: return std::move(ret) + "after(" + util::ToString(node.k) + ")";
949
8
                case Fragment::OLDER: return std::move(ret) + "older(" + util::ToString(node.k) + ")";
950
0
                case Fragment::HASH256: return std::move(ret) + "hash256(" + HexStr(node.data) + ")";
951
0
                case Fragment::HASH160: return std::move(ret) + "hash160(" + HexStr(node.data) + ")";
952
2
                case Fragment::SHA256: return std::move(ret) + "sha256(" + HexStr(node.data) + ")";
953
1
                case Fragment::RIPEMD160: return std::move(ret) + "ripemd160(" + HexStr(node.data) + ")";
954
1
                case Fragment::JUST_1: return std::move(ret) + "1";
955
1
                case Fragment::JUST_0: return std::move(ret) + "0";
956
2
                case Fragment::AND_V: return std::move(ret) + "and_v(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
957
7
                case Fragment::AND_B: return std::move(ret) + "and_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
958
4
                case Fragment::OR_B: return std::move(ret) + "or_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
959
0
                case Fragment::OR_D: return std::move(ret) + "or_d(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
960
0
                case Fragment::OR_C: return std::move(ret) + "or_c(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
961
2
                case Fragment::OR_I: return std::move(ret) + "or_i(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
962
2
                case Fragment::ANDOR:
963
                    // and_n(X,Y) is syntactic sugar for andor(X,Y,0).
964
2
                    if (node.subs[2].fragment == Fragment::JUST_0) return std::move(ret) + "and_n(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
965
2
                    return std::move(ret) + "andor(" + std::move(subs[0]) + "," + std::move(subs[1]) + "," + std::move(subs[2]) + ")";
966
0
                case Fragment::MULTI: {
967
0
                    CHECK_NONFATAL(!is_tapscript);
968
0
                    auto str = std::move(ret) + "multi(" + util::ToString(node.k);
969
0
                    for (const auto& key : node.keys) {
970
0
                        auto key_str = toString(key);
971
0
                        if (!key_str) return {};
972
0
                        str += "," + std::move(*key_str);
973
0
                    }
974
0
                    return std::move(str) + ")";
975
0
                }
976
0
                case Fragment::MULTI_A: {
977
0
                    CHECK_NONFATAL(is_tapscript);
978
0
                    auto str = std::move(ret) + "multi_a(" + util::ToString(node.k);
979
0
                    for (const auto& key : node.keys) {
980
0
                        auto key_str = toString(key);
981
0
                        if (!key_str) return {};
982
0
                        str += "," + std::move(*key_str);
983
0
                    }
984
0
                    return std::move(str) + ")";
985
0
                }
986
0
                case Fragment::THRESH: {
987
0
                    auto str = std::move(ret) + "thresh(" + util::ToString(node.k);
988
0
                    for (auto& sub : subs) {
989
0
                        str += "," + std::move(sub);
990
0
                    }
991
0
                    return std::move(str) + ")";
992
0
                }
993
0
                default: break;
994
50
            }
995
50
            assert(false);
996
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
903
2.97M
        auto upfn = [is_tapscript, &toString](bool wrapped, const Node& node, std::span<std::string> subs) -> std::optional<std::string> {
904
2.97M
            std::string ret = wrapped ? ":" : "";
905
906
2.97M
            switch (node.fragment) {
907
605
                case Fragment::WRAP_A: return "a" + std::move(subs[0]);
908
332
                case Fragment::WRAP_S: return "s" + std::move(subs[0]);
909
2.37k
                case Fragment::WRAP_C:
910
2.37k
                    if (node.subs[0].fragment == Fragment::PK_K) {
911
                        // pk(K) is syntactic sugar for c:pk_k(K)
912
1.73k
                        auto key_str = toString(node.subs[0].keys[0]);
913
1.73k
                        if (!key_str) return {};
914
1.73k
                        return std::move(ret) + "pk(" + std::move(*key_str) + ")";
915
1.73k
                    }
916
643
                    if (node.subs[0].fragment == Fragment::PK_H) {
917
                        // pkh(K) is syntactic sugar for c:pk_h(K)
918
623
                        auto key_str = toString(node.subs[0].keys[0]);
919
623
                        if (!key_str) return {};
920
623
                        return std::move(ret) + "pkh(" + std::move(*key_str) + ")";
921
623
                    }
922
20
                    return "c" + std::move(subs[0]);
923
84
                case Fragment::WRAP_D: return "d" + std::move(subs[0]);
924
1.07k
                case Fragment::WRAP_V: return "v" + std::move(subs[0]);
925
0
                case Fragment::WRAP_J: return "j" + std::move(subs[0]);
926
2.96M
                case Fragment::WRAP_N: return "n" + std::move(subs[0]);
927
995
                case Fragment::AND_V:
928
                    // t:X is syntactic sugar for and_v(X,1).
929
995
                    if (node.subs[1].fragment == Fragment::JUST_1) return "t" + std::move(subs[0]);
930
989
                    break;
931
989
                case Fragment::OR_I:
932
227
                    if (node.subs[0].fragment == Fragment::JUST_0) return "l" + std::move(subs[1]);
933
106
                    if (node.subs[1].fragment == Fragment::JUST_0) return "u" + std::move(subs[0]);
934
106
                    break;
935
4.65k
                default: break;
936
2.97M
            }
937
5.75k
            switch (node.fragment) {
938
1.77k
                case Fragment::PK_K: {
939
1.77k
                    auto key_str = toString(node.keys[0]);
940
1.77k
                    if (!key_str) return {};
941
1.77k
                    return std::move(ret) + "pk_k(" + std::move(*key_str) + ")";
942
1.77k
                }
943
623
                case Fragment::PK_H: {
944
623
                    auto key_str = toString(node.keys[0]);
945
623
                    if (!key_str) return {};
946
623
                    return std::move(ret) + "pk_h(" + std::move(*key_str) + ")";
947
623
                }
948
432
                case Fragment::AFTER: return std::move(ret) + "after(" + util::ToString(node.k) + ")";
949
392
                case Fragment::OLDER: return std::move(ret) + "older(" + util::ToString(node.k) + ")";
950
30
                case Fragment::HASH256: return std::move(ret) + "hash256(" + HexStr(node.data) + ")";
951
63
                case Fragment::HASH160: return std::move(ret) + "hash160(" + HexStr(node.data) + ")";
952
69
                case Fragment::SHA256: return std::move(ret) + "sha256(" + HexStr(node.data) + ")";
953
34
                case Fragment::RIPEMD160: return std::move(ret) + "ripemd160(" + HexStr(node.data) + ")";
954
6
                case Fragment::JUST_1: return std::move(ret) + "1";
955
161
                case Fragment::JUST_0: return std::move(ret) + "0";
956
989
                case Fragment::AND_V: return std::move(ret) + "and_v(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
957
360
                case Fragment::AND_B: return std::move(ret) + "and_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
958
58
                case Fragment::OR_B: return std::move(ret) + "or_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
959
77
                case Fragment::OR_D: return std::move(ret) + "or_d(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
960
42
                case Fragment::OR_C: return std::move(ret) + "or_c(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
961
106
                case Fragment::OR_I: return std::move(ret) + "or_i(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
962
180
                case Fragment::ANDOR:
963
                    // and_n(X,Y) is syntactic sugar for andor(X,Y,0).
964
180
                    if (node.subs[2].fragment == Fragment::JUST_0) return std::move(ret) + "and_n(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
965
140
                    return std::move(ret) + "andor(" + std::move(subs[0]) + "," + std::move(subs[1]) + "," + std::move(subs[2]) + ")";
966
96
                case Fragment::MULTI: {
967
96
                    CHECK_NONFATAL(!is_tapscript);
968
96
                    auto str = std::move(ret) + "multi(" + util::ToString(node.k);
969
246
                    for (const auto& key : node.keys) {
970
246
                        auto key_str = toString(key);
971
246
                        if (!key_str) return {};
972
246
                        str += "," + std::move(*key_str);
973
246
                    }
974
96
                    return std::move(str) + ")";
975
96
                }
976
51
                case Fragment::MULTI_A: {
977
51
                    CHECK_NONFATAL(is_tapscript);
978
51
                    auto str = std::move(ret) + "multi_a(" + util::ToString(node.k);
979
130
                    for (const auto& key : node.keys) {
980
130
                        auto key_str = toString(key);
981
130
                        if (!key_str) return {};
982
130
                        str += "," + std::move(*key_str);
983
130
                    }
984
51
                    return std::move(str) + ")";
985
51
                }
986
211
                case Fragment::THRESH: {
987
211
                    auto str = std::move(ret) + "thresh(" + util::ToString(node.k);
988
730
                    for (auto& sub : subs) {
989
730
                        str += "," + std::move(sub);
990
730
                    }
991
211
                    return std::move(str) + ")";
992
51
                }
993
0
                default: break;
994
5.75k
            }
995
5.75k
            assert(false);
996
0
        };
997
998
1.10k
        return TreeEvalMaybe<std::string>(false, downfn, upfn);
999
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
881
1
    std::optional<std::string> ToString(const CTx& ctx, bool& has_priv_key) const {
882
        // To construct the std::string representation for a Miniscript object, we use
883
        // the TreeEvalMaybe algorithm. The State is a boolean: whether the parent node is a
884
        // wrapper. If so, non-wrapper expressions must be prefixed with a ":".
885
1
        auto downfn = [](bool, const Node& node, size_t) {
886
1
            return (node.fragment == Fragment::WRAP_A || node.fragment == Fragment::WRAP_S ||
887
1
                    node.fragment == Fragment::WRAP_D || node.fragment == Fragment::WRAP_V ||
888
1
                    node.fragment == Fragment::WRAP_J || node.fragment == Fragment::WRAP_N ||
889
1
                    node.fragment == Fragment::WRAP_C ||
890
1
                    (node.fragment == Fragment::AND_V && node.subs[1].fragment == Fragment::JUST_1) ||
891
1
                    (node.fragment == Fragment::OR_I && node.subs[0].fragment == Fragment::JUST_0) ||
892
1
                    (node.fragment == Fragment::OR_I && node.subs[1].fragment == Fragment::JUST_0));
893
1
        };
894
1
        auto toString = [&ctx, &has_priv_key](Key key) -> std::optional<std::string> {
895
1
            bool fragment_has_priv_key{false};
896
1
            auto key_str{ctx.ToString(key, fragment_has_priv_key)};
897
1
            if (key_str) has_priv_key = has_priv_key || fragment_has_priv_key;
898
1
            return key_str;
899
1
        };
900
        // The upward function computes for a node, given whether its parent is a wrapper,
901
        // and the string representations of its child nodes, the string representation of the node.
902
1
        const bool is_tapscript{IsTapscript(m_script_ctx)};
903
1
        auto upfn = [is_tapscript, &toString](bool wrapped, const Node& node, std::span<std::string> subs) -> std::optional<std::string> {
904
1
            std::string ret = wrapped ? ":" : "";
905
906
1
            switch (node.fragment) {
907
1
                case Fragment::WRAP_A: return "a" + std::move(subs[0]);
908
1
                case Fragment::WRAP_S: return "s" + std::move(subs[0]);
909
1
                case Fragment::WRAP_C:
910
1
                    if (node.subs[0].fragment == Fragment::PK_K) {
911
                        // pk(K) is syntactic sugar for c:pk_k(K)
912
1
                        auto key_str = toString(node.subs[0].keys[0]);
913
1
                        if (!key_str) return {};
914
1
                        return std::move(ret) + "pk(" + std::move(*key_str) + ")";
915
1
                    }
916
1
                    if (node.subs[0].fragment == Fragment::PK_H) {
917
                        // pkh(K) is syntactic sugar for c:pk_h(K)
918
1
                        auto key_str = toString(node.subs[0].keys[0]);
919
1
                        if (!key_str) return {};
920
1
                        return std::move(ret) + "pkh(" + std::move(*key_str) + ")";
921
1
                    }
922
1
                    return "c" + std::move(subs[0]);
923
1
                case Fragment::WRAP_D: return "d" + std::move(subs[0]);
924
1
                case Fragment::WRAP_V: return "v" + std::move(subs[0]);
925
1
                case Fragment::WRAP_J: return "j" + std::move(subs[0]);
926
1
                case Fragment::WRAP_N: return "n" + std::move(subs[0]);
927
1
                case Fragment::AND_V:
928
                    // t:X is syntactic sugar for and_v(X,1).
929
1
                    if (node.subs[1].fragment == Fragment::JUST_1) return "t" + std::move(subs[0]);
930
1
                    break;
931
1
                case Fragment::OR_I:
932
1
                    if (node.subs[0].fragment == Fragment::JUST_0) return "l" + std::move(subs[1]);
933
1
                    if (node.subs[1].fragment == Fragment::JUST_0) return "u" + std::move(subs[0]);
934
1
                    break;
935
1
                default: break;
936
1
            }
937
1
            switch (node.fragment) {
938
1
                case Fragment::PK_K: {
939
1
                    auto key_str = toString(node.keys[0]);
940
1
                    if (!key_str) return {};
941
1
                    return std::move(ret) + "pk_k(" + std::move(*key_str) + ")";
942
1
                }
943
1
                case Fragment::PK_H: {
944
1
                    auto key_str = toString(node.keys[0]);
945
1
                    if (!key_str) return {};
946
1
                    return std::move(ret) + "pk_h(" + std::move(*key_str) + ")";
947
1
                }
948
1
                case Fragment::AFTER: return std::move(ret) + "after(" + util::ToString(node.k) + ")";
949
1
                case Fragment::OLDER: return std::move(ret) + "older(" + util::ToString(node.k) + ")";
950
1
                case Fragment::HASH256: return std::move(ret) + "hash256(" + HexStr(node.data) + ")";
951
1
                case Fragment::HASH160: return std::move(ret) + "hash160(" + HexStr(node.data) + ")";
952
1
                case Fragment::SHA256: return std::move(ret) + "sha256(" + HexStr(node.data) + ")";
953
1
                case Fragment::RIPEMD160: return std::move(ret) + "ripemd160(" + HexStr(node.data) + ")";
954
1
                case Fragment::JUST_1: return std::move(ret) + "1";
955
1
                case Fragment::JUST_0: return std::move(ret) + "0";
956
1
                case Fragment::AND_V: return std::move(ret) + "and_v(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
957
1
                case Fragment::AND_B: return std::move(ret) + "and_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
958
1
                case Fragment::OR_B: return std::move(ret) + "or_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
959
1
                case Fragment::OR_D: return std::move(ret) + "or_d(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
960
1
                case Fragment::OR_C: return std::move(ret) + "or_c(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
961
1
                case Fragment::OR_I: return std::move(ret) + "or_i(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
962
1
                case Fragment::ANDOR:
963
                    // and_n(X,Y) is syntactic sugar for andor(X,Y,0).
964
1
                    if (node.subs[2].fragment == Fragment::JUST_0) return std::move(ret) + "and_n(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
965
1
                    return std::move(ret) + "andor(" + std::move(subs[0]) + "," + std::move(subs[1]) + "," + std::move(subs[2]) + ")";
966
1
                case Fragment::MULTI: {
967
1
                    CHECK_NONFATAL(!is_tapscript);
968
1
                    auto str = std::move(ret) + "multi(" + util::ToString(node.k);
969
1
                    for (const auto& key : node.keys) {
970
1
                        auto key_str = toString(key);
971
1
                        if (!key_str) return {};
972
1
                        str += "," + std::move(*key_str);
973
1
                    }
974
1
                    return std::move(str) + ")";
975
1
                }
976
1
                case Fragment::MULTI_A: {
977
1
                    CHECK_NONFATAL(is_tapscript);
978
1
                    auto str = std::move(ret) + "multi_a(" + util::ToString(node.k);
979
1
                    for (const auto& key : node.keys) {
980
1
                        auto key_str = toString(key);
981
1
                        if (!key_str) return {};
982
1
                        str += "," + std::move(*key_str);
983
1
                    }
984
1
                    return std::move(str) + ")";
985
1
                }
986
1
                case Fragment::THRESH: {
987
1
                    auto str = std::move(ret) + "thresh(" + util::ToString(node.k);
988
1
                    for (auto& sub : subs) {
989
1
                        str += "," + std::move(sub);
990
1
                    }
991
1
                    return std::move(str) + ")";
992
1
                }
993
1
                default: break;
994
1
            }
995
1
            assert(false);
996
1
        };
997
998
1
        return TreeEvalMaybe<std::string>(false, downfn, upfn);
999
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
881
14
    std::optional<std::string> ToString(const CTx& ctx, bool& has_priv_key) const {
882
        // To construct the std::string representation for a Miniscript object, we use
883
        // the TreeEvalMaybe algorithm. The State is a boolean: whether the parent node is a
884
        // wrapper. If so, non-wrapper expressions must be prefixed with a ":".
885
14
        auto downfn = [](bool, const Node& node, size_t) {
886
14
            return (node.fragment == Fragment::WRAP_A || node.fragment == Fragment::WRAP_S ||
887
14
                    node.fragment == Fragment::WRAP_D || node.fragment == Fragment::WRAP_V ||
888
14
                    node.fragment == Fragment::WRAP_J || node.fragment == Fragment::WRAP_N ||
889
14
                    node.fragment == Fragment::WRAP_C ||
890
14
                    (node.fragment == Fragment::AND_V && node.subs[1].fragment == Fragment::JUST_1) ||
891
14
                    (node.fragment == Fragment::OR_I && node.subs[0].fragment == Fragment::JUST_0) ||
892
14
                    (node.fragment == Fragment::OR_I && node.subs[1].fragment == Fragment::JUST_0));
893
14
        };
894
14
        auto toString = [&ctx, &has_priv_key](Key key) -> std::optional<std::string> {
895
14
            bool fragment_has_priv_key{false};
896
14
            auto key_str{ctx.ToString(key, fragment_has_priv_key)};
897
14
            if (key_str) has_priv_key = has_priv_key || fragment_has_priv_key;
898
14
            return key_str;
899
14
        };
900
        // The upward function computes for a node, given whether its parent is a wrapper,
901
        // and the string representations of its child nodes, the string representation of the node.
902
14
        const bool is_tapscript{IsTapscript(m_script_ctx)};
903
14
        auto upfn = [is_tapscript, &toString](bool wrapped, const Node& node, std::span<std::string> subs) -> std::optional<std::string> {
904
14
            std::string ret = wrapped ? ":" : "";
905
906
14
            switch (node.fragment) {
907
14
                case Fragment::WRAP_A: return "a" + std::move(subs[0]);
908
14
                case Fragment::WRAP_S: return "s" + std::move(subs[0]);
909
14
                case Fragment::WRAP_C:
910
14
                    if (node.subs[0].fragment == Fragment::PK_K) {
911
                        // pk(K) is syntactic sugar for c:pk_k(K)
912
14
                        auto key_str = toString(node.subs[0].keys[0]);
913
14
                        if (!key_str) return {};
914
14
                        return std::move(ret) + "pk(" + std::move(*key_str) + ")";
915
14
                    }
916
14
                    if (node.subs[0].fragment == Fragment::PK_H) {
917
                        // pkh(K) is syntactic sugar for c:pk_h(K)
918
14
                        auto key_str = toString(node.subs[0].keys[0]);
919
14
                        if (!key_str) return {};
920
14
                        return std::move(ret) + "pkh(" + std::move(*key_str) + ")";
921
14
                    }
922
14
                    return "c" + std::move(subs[0]);
923
14
                case Fragment::WRAP_D: return "d" + std::move(subs[0]);
924
14
                case Fragment::WRAP_V: return "v" + std::move(subs[0]);
925
14
                case Fragment::WRAP_J: return "j" + std::move(subs[0]);
926
14
                case Fragment::WRAP_N: return "n" + std::move(subs[0]);
927
14
                case Fragment::AND_V:
928
                    // t:X is syntactic sugar for and_v(X,1).
929
14
                    if (node.subs[1].fragment == Fragment::JUST_1) return "t" + std::move(subs[0]);
930
14
                    break;
931
14
                case Fragment::OR_I:
932
14
                    if (node.subs[0].fragment == Fragment::JUST_0) return "l" + std::move(subs[1]);
933
14
                    if (node.subs[1].fragment == Fragment::JUST_0) return "u" + std::move(subs[0]);
934
14
                    break;
935
14
                default: break;
936
14
            }
937
14
            switch (node.fragment) {
938
14
                case Fragment::PK_K: {
939
14
                    auto key_str = toString(node.keys[0]);
940
14
                    if (!key_str) return {};
941
14
                    return std::move(ret) + "pk_k(" + std::move(*key_str) + ")";
942
14
                }
943
14
                case Fragment::PK_H: {
944
14
                    auto key_str = toString(node.keys[0]);
945
14
                    if (!key_str) return {};
946
14
                    return std::move(ret) + "pk_h(" + std::move(*key_str) + ")";
947
14
                }
948
14
                case Fragment::AFTER: return std::move(ret) + "after(" + util::ToString(node.k) + ")";
949
14
                case Fragment::OLDER: return std::move(ret) + "older(" + util::ToString(node.k) + ")";
950
14
                case Fragment::HASH256: return std::move(ret) + "hash256(" + HexStr(node.data) + ")";
951
14
                case Fragment::HASH160: return std::move(ret) + "hash160(" + HexStr(node.data) + ")";
952
14
                case Fragment::SHA256: return std::move(ret) + "sha256(" + HexStr(node.data) + ")";
953
14
                case Fragment::RIPEMD160: return std::move(ret) + "ripemd160(" + HexStr(node.data) + ")";
954
14
                case Fragment::JUST_1: return std::move(ret) + "1";
955
14
                case Fragment::JUST_0: return std::move(ret) + "0";
956
14
                case Fragment::AND_V: return std::move(ret) + "and_v(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
957
14
                case Fragment::AND_B: return std::move(ret) + "and_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
958
14
                case Fragment::OR_B: return std::move(ret) + "or_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
959
14
                case Fragment::OR_D: return std::move(ret) + "or_d(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
960
14
                case Fragment::OR_C: return std::move(ret) + "or_c(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
961
14
                case Fragment::OR_I: return std::move(ret) + "or_i(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
962
14
                case Fragment::ANDOR:
963
                    // and_n(X,Y) is syntactic sugar for andor(X,Y,0).
964
14
                    if (node.subs[2].fragment == Fragment::JUST_0) return std::move(ret) + "and_n(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
965
14
                    return std::move(ret) + "andor(" + std::move(subs[0]) + "," + std::move(subs[1]) + "," + std::move(subs[2]) + ")";
966
14
                case Fragment::MULTI: {
967
14
                    CHECK_NONFATAL(!is_tapscript);
968
14
                    auto str = std::move(ret) + "multi(" + util::ToString(node.k);
969
14
                    for (const auto& key : node.keys) {
970
14
                        auto key_str = toString(key);
971
14
                        if (!key_str) return {};
972
14
                        str += "," + std::move(*key_str);
973
14
                    }
974
14
                    return std::move(str) + ")";
975
14
                }
976
14
                case Fragment::MULTI_A: {
977
14
                    CHECK_NONFATAL(is_tapscript);
978
14
                    auto str = std::move(ret) + "multi_a(" + util::ToString(node.k);
979
14
                    for (const auto& key : node.keys) {
980
14
                        auto key_str = toString(key);
981
14
                        if (!key_str) return {};
982
14
                        str += "," + std::move(*key_str);
983
14
                    }
984
14
                    return std::move(str) + ")";
985
14
                }
986
14
                case Fragment::THRESH: {
987
14
                    auto str = std::move(ret) + "thresh(" + util::ToString(node.k);
988
14
                    for (auto& sub : subs) {
989
14
                        str += "," + std::move(sub);
990
14
                    }
991
14
                    return std::move(str) + ")";
992
14
                }
993
14
                default: break;
994
14
            }
995
14
            assert(false);
996
14
        };
997
998
14
        return TreeEvalMaybe<std::string>(false, downfn, upfn);
999
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
881
1.08k
    std::optional<std::string> ToString(const CTx& ctx, bool& has_priv_key) const {
882
        // To construct the std::string representation for a Miniscript object, we use
883
        // the TreeEvalMaybe algorithm. The State is a boolean: whether the parent node is a
884
        // wrapper. If so, non-wrapper expressions must be prefixed with a ":".
885
1.08k
        auto downfn = [](bool, const Node& node, size_t) {
886
1.08k
            return (node.fragment == Fragment::WRAP_A || node.fragment == Fragment::WRAP_S ||
887
1.08k
                    node.fragment == Fragment::WRAP_D || node.fragment == Fragment::WRAP_V ||
888
1.08k
                    node.fragment == Fragment::WRAP_J || node.fragment == Fragment::WRAP_N ||
889
1.08k
                    node.fragment == Fragment::WRAP_C ||
890
1.08k
                    (node.fragment == Fragment::AND_V && node.subs[1].fragment == Fragment::JUST_1) ||
891
1.08k
                    (node.fragment == Fragment::OR_I && node.subs[0].fragment == Fragment::JUST_0) ||
892
1.08k
                    (node.fragment == Fragment::OR_I && node.subs[1].fragment == Fragment::JUST_0));
893
1.08k
        };
894
1.08k
        auto toString = [&ctx, &has_priv_key](Key key) -> std::optional<std::string> {
895
1.08k
            bool fragment_has_priv_key{false};
896
1.08k
            auto key_str{ctx.ToString(key, fragment_has_priv_key)};
897
1.08k
            if (key_str) has_priv_key = has_priv_key || fragment_has_priv_key;
898
1.08k
            return key_str;
899
1.08k
        };
900
        // The upward function computes for a node, given whether its parent is a wrapper,
901
        // and the string representations of its child nodes, the string representation of the node.
902
1.08k
        const bool is_tapscript{IsTapscript(m_script_ctx)};
903
1.08k
        auto upfn = [is_tapscript, &toString](bool wrapped, const Node& node, std::span<std::string> subs) -> std::optional<std::string> {
904
1.08k
            std::string ret = wrapped ? ":" : "";
905
906
1.08k
            switch (node.fragment) {
907
1.08k
                case Fragment::WRAP_A: return "a" + std::move(subs[0]);
908
1.08k
                case Fragment::WRAP_S: return "s" + std::move(subs[0]);
909
1.08k
                case Fragment::WRAP_C:
910
1.08k
                    if (node.subs[0].fragment == Fragment::PK_K) {
911
                        // pk(K) is syntactic sugar for c:pk_k(K)
912
1.08k
                        auto key_str = toString(node.subs[0].keys[0]);
913
1.08k
                        if (!key_str) return {};
914
1.08k
                        return std::move(ret) + "pk(" + std::move(*key_str) + ")";
915
1.08k
                    }
916
1.08k
                    if (node.subs[0].fragment == Fragment::PK_H) {
917
                        // pkh(K) is syntactic sugar for c:pk_h(K)
918
1.08k
                        auto key_str = toString(node.subs[0].keys[0]);
919
1.08k
                        if (!key_str) return {};
920
1.08k
                        return std::move(ret) + "pkh(" + std::move(*key_str) + ")";
921
1.08k
                    }
922
1.08k
                    return "c" + std::move(subs[0]);
923
1.08k
                case Fragment::WRAP_D: return "d" + std::move(subs[0]);
924
1.08k
                case Fragment::WRAP_V: return "v" + std::move(subs[0]);
925
1.08k
                case Fragment::WRAP_J: return "j" + std::move(subs[0]);
926
1.08k
                case Fragment::WRAP_N: return "n" + std::move(subs[0]);
927
1.08k
                case Fragment::AND_V:
928
                    // t:X is syntactic sugar for and_v(X,1).
929
1.08k
                    if (node.subs[1].fragment == Fragment::JUST_1) return "t" + std::move(subs[0]);
930
1.08k
                    break;
931
1.08k
                case Fragment::OR_I:
932
1.08k
                    if (node.subs[0].fragment == Fragment::JUST_0) return "l" + std::move(subs[1]);
933
1.08k
                    if (node.subs[1].fragment == Fragment::JUST_0) return "u" + std::move(subs[0]);
934
1.08k
                    break;
935
1.08k
                default: break;
936
1.08k
            }
937
1.08k
            switch (node.fragment) {
938
1.08k
                case Fragment::PK_K: {
939
1.08k
                    auto key_str = toString(node.keys[0]);
940
1.08k
                    if (!key_str) return {};
941
1.08k
                    return std::move(ret) + "pk_k(" + std::move(*key_str) + ")";
942
1.08k
                }
943
1.08k
                case Fragment::PK_H: {
944
1.08k
                    auto key_str = toString(node.keys[0]);
945
1.08k
                    if (!key_str) return {};
946
1.08k
                    return std::move(ret) + "pk_h(" + std::move(*key_str) + ")";
947
1.08k
                }
948
1.08k
                case Fragment::AFTER: return std::move(ret) + "after(" + util::ToString(node.k) + ")";
949
1.08k
                case Fragment::OLDER: return std::move(ret) + "older(" + util::ToString(node.k) + ")";
950
1.08k
                case Fragment::HASH256: return std::move(ret) + "hash256(" + HexStr(node.data) + ")";
951
1.08k
                case Fragment::HASH160: return std::move(ret) + "hash160(" + HexStr(node.data) + ")";
952
1.08k
                case Fragment::SHA256: return std::move(ret) + "sha256(" + HexStr(node.data) + ")";
953
1.08k
                case Fragment::RIPEMD160: return std::move(ret) + "ripemd160(" + HexStr(node.data) + ")";
954
1.08k
                case Fragment::JUST_1: return std::move(ret) + "1";
955
1.08k
                case Fragment::JUST_0: return std::move(ret) + "0";
956
1.08k
                case Fragment::AND_V: return std::move(ret) + "and_v(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
957
1.08k
                case Fragment::AND_B: return std::move(ret) + "and_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
958
1.08k
                case Fragment::OR_B: return std::move(ret) + "or_b(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
959
1.08k
                case Fragment::OR_D: return std::move(ret) + "or_d(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
960
1.08k
                case Fragment::OR_C: return std::move(ret) + "or_c(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
961
1.08k
                case Fragment::OR_I: return std::move(ret) + "or_i(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
962
1.08k
                case Fragment::ANDOR:
963
                    // and_n(X,Y) is syntactic sugar for andor(X,Y,0).
964
1.08k
                    if (node.subs[2].fragment == Fragment::JUST_0) return std::move(ret) + "and_n(" + std::move(subs[0]) + "," + std::move(subs[1]) + ")";
965
1.08k
                    return std::move(ret) + "andor(" + std::move(subs[0]) + "," + std::move(subs[1]) + "," + std::move(subs[2]) + ")";
966
1.08k
                case Fragment::MULTI: {
967
1.08k
                    CHECK_NONFATAL(!is_tapscript);
968
1.08k
                    auto str = std::move(ret) + "multi(" + util::ToString(node.k);
969
1.08k
                    for (const auto& key : node.keys) {
970
1.08k
                        auto key_str = toString(key);
971
1.08k
                        if (!key_str) return {};
972
1.08k
                        str += "," + std::move(*key_str);
973
1.08k
                    }
974
1.08k
                    return std::move(str) + ")";
975
1.08k
                }
976
1.08k
                case Fragment::MULTI_A: {
977
1.08k
                    CHECK_NONFATAL(is_tapscript);
978
1.08k
                    auto str = std::move(ret) + "multi_a(" + util::ToString(node.k);
979
1.08k
                    for (const auto& key : node.keys) {
980
1.08k
                        auto key_str = toString(key);
981
1.08k
                        if (!key_str) return {};
982
1.08k
                        str += "," + std::move(*key_str);
983
1.08k
                    }
984
1.08k
                    return std::move(str) + ")";
985
1.08k
                }
986
1.08k
                case Fragment::THRESH: {
987
1.08k
                    auto str = std::move(ret) + "thresh(" + util::ToString(node.k);
988
1.08k
                    for (auto& sub : subs) {
989
1.08k
                        str += "," + std::move(sub);
990
1.08k
                    }
991
1.08k
                    return std::move(str) + ")";
992
1.08k
                }
993
1.08k
                default: break;
994
1.08k
            }
995
1.08k
            assert(false);
996
1.08k
        };
997
998
1.08k
        return TreeEvalMaybe<std::string>(false, downfn, upfn);
999
1.08k
    }
1000
1001
private:
1002
7.03M
    internal::Ops CalcOps() const {
1003
7.03M
        switch (fragment) {
1004
245
            case Fragment::JUST_1: return {0, 0, {}};
1005
709
            case Fragment::JUST_0: return {0, {}, 0};
1006
5.35k
            case Fragment::PK_K: return {0, 0, 0};
1007
775
            case Fragment::PK_H: return {3, 0, 0};
1008
7.95k
            case Fragment::OLDER:
1009
9.05k
            case Fragment::AFTER: return {1, 0, {}};
1010
103
            case Fragment::SHA256:
1011
180
            case Fragment::RIPEMD160:
1012
296
            case Fragment::HASH256:
1013
395
            case Fragment::HASH160: return {4, 0, {}};
1014
1.46k
            case Fragment::AND_V: return {subs[0].ops.count + subs[1].ops.count, subs[0].ops.sat + subs[1].ops.sat, {}};
1015
7.15k
            case Fragment::AND_B: {
1016
7.15k
                const auto count{1 + subs[0].ops.count + subs[1].ops.count};
1017
7.15k
                const auto sat{subs[0].ops.sat + subs[1].ops.sat};
1018
7.15k
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1019
7.15k
                return {count, sat, dsat};
1020
296
            }
1021
93
            case Fragment::OR_B: {
1022
93
                const auto count{1 + subs[0].ops.count + subs[1].ops.count};
1023
93
                const auto sat{(subs[0].ops.sat + subs[1].ops.dsat) | (subs[1].ops.sat + subs[0].ops.dsat)};
1024
93
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1025
93
                return {count, sat, dsat};
1026
296
            }
1027
132
            case Fragment::OR_D: {
1028
132
                const auto count{3 + subs[0].ops.count + subs[1].ops.count};
1029
132
                const auto sat{subs[0].ops.sat | (subs[1].ops.sat + subs[0].ops.dsat)};
1030
132
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1031
132
                return {count, sat, dsat};
1032
296
            }
1033
62
            case Fragment::OR_C: {
1034
62
                const auto count{2 + subs[0].ops.count + subs[1].ops.count};
1035
62
                const auto sat{subs[0].ops.sat | (subs[1].ops.sat + subs[0].ops.dsat)};
1036
62
                return {count, sat, {}};
1037
296
            }
1038
647
            case Fragment::OR_I: {
1039
647
                const auto count{3 + subs[0].ops.count + subs[1].ops.count};
1040
647
                const auto sat{subs[0].ops.sat | subs[1].ops.sat};
1041
647
                const auto dsat{subs[0].ops.dsat | subs[1].ops.dsat};
1042
647
                return {count, sat, dsat};
1043
296
            }
1044
248
            case Fragment::ANDOR: {
1045
248
                const auto count{3 + subs[0].ops.count + subs[1].ops.count + subs[2].ops.count};
1046
248
                const auto sat{(subs[1].ops.sat + subs[0].ops.sat) | (subs[0].ops.dsat + subs[2].ops.sat)};
1047
248
                const auto dsat{subs[0].ops.dsat + subs[2].ops.dsat};
1048
248
                return {count, sat, dsat};
1049
296
            }
1050
177
            case Fragment::MULTI: return {1, (uint32_t)keys.size(), (uint32_t)keys.size()};
1051
808
            case Fragment::MULTI_A: return {(uint32_t)keys.size() + 1, 0, 0};
1052
879
            case Fragment::WRAP_S:
1053
6.93k
            case Fragment::WRAP_C:
1054
6.99M
            case Fragment::WRAP_N: return {1 + subs[0].ops.count, subs[0].ops.sat, subs[0].ops.dsat};
1055
7.54k
            case Fragment::WRAP_A: return {2 + subs[0].ops.count, subs[0].ops.sat, subs[0].ops.dsat};
1056
115
            case Fragment::WRAP_D: return {3 + subs[0].ops.count, subs[0].ops.sat, 0};
1057
16
            case Fragment::WRAP_J: return {4 + subs[0].ops.count, subs[0].ops.sat, 0};
1058
1.60k
            case Fragment::WRAP_V: return {subs[0].ops.count + (subs[0].GetType() << "x"_mst), subs[0].ops.sat, {}};
1059
404
            case Fragment::THRESH: {
1060
404
                uint32_t count = 0;
1061
404
                auto sats = Vector(internal::MaxInt<uint32_t>(0));
1062
1.56k
                for (const auto& sub : subs) {
1063
1.56k
                    count += sub.ops.count + 1;
1064
1.56k
                    auto next_sats = Vector(sats[0] + sub.ops.dsat);
1065
4.62k
                    for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub.ops.dsat) | (sats[j - 1] + sub.ops.sat));
1066
1.56k
                    next_sats.push_back(sats[sats.size() - 1] + sub.ops.sat);
1067
1.56k
                    sats = std::move(next_sats);
1068
1.56k
                }
1069
404
                assert(k < sats.size());
1070
404
                return {count, sats[k], sats[0]};
1071
404
            }
1072
7.03M
        }
1073
7.03M
        assert(false);
1074
0
    }
miniscript::Node<CPubKey>::CalcOps() const
Line
Count
Source
1002
28.2k
    internal::Ops CalcOps() const {
1003
28.2k
        switch (fragment) {
1004
232
            case Fragment::JUST_1: return {0, 0, {}};
1005
449
            case Fragment::JUST_0: return {0, {}, 0};
1006
1.67k
            case Fragment::PK_K: return {0, 0, 0};
1007
100
            case Fragment::PK_H: return {3, 0, 0};
1008
7.57k
            case Fragment::OLDER:
1009
7.95k
            case Fragment::AFTER: return {1, 0, {}};
1010
61
            case Fragment::SHA256:
1011
87
            case Fragment::RIPEMD160:
1012
127
            case Fragment::HASH256:
1013
151
            case Fragment::HASH160: return {4, 0, {}};
1014
255
            case Fragment::AND_V: return {subs[0].ops.count + subs[1].ops.count, subs[0].ops.sat + subs[1].ops.sat, {}};
1015
6.85k
            case Fragment::AND_B: {
1016
6.85k
                const auto count{1 + subs[0].ops.count + subs[1].ops.count};
1017
6.85k
                const auto sat{subs[0].ops.sat + subs[1].ops.sat};
1018
6.85k
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1019
6.85k
                return {count, sat, dsat};
1020
127
            }
1021
29
            case Fragment::OR_B: {
1022
29
                const auto count{1 + subs[0].ops.count + subs[1].ops.count};
1023
29
                const auto sat{(subs[0].ops.sat + subs[1].ops.dsat) | (subs[1].ops.sat + subs[0].ops.dsat)};
1024
29
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1025
29
                return {count, sat, dsat};
1026
127
            }
1027
46
            case Fragment::OR_D: {
1028
46
                const auto count{3 + subs[0].ops.count + subs[1].ops.count};
1029
46
                const auto sat{subs[0].ops.sat | (subs[1].ops.sat + subs[0].ops.dsat)};
1030
46
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1031
46
                return {count, sat, dsat};
1032
127
            }
1033
20
            case Fragment::OR_C: {
1034
20
                const auto count{2 + subs[0].ops.count + subs[1].ops.count};
1035
20
                const auto sat{subs[0].ops.sat | (subs[1].ops.sat + subs[0].ops.dsat)};
1036
20
                return {count, sat, {}};
1037
127
            }
1038
391
            case Fragment::OR_I: {
1039
391
                const auto count{3 + subs[0].ops.count + subs[1].ops.count};
1040
391
                const auto sat{subs[0].ops.sat | subs[1].ops.sat};
1041
391
                const auto dsat{subs[0].ops.dsat | subs[1].ops.dsat};
1042
391
                return {count, sat, dsat};
1043
127
            }
1044
110
            case Fragment::ANDOR: {
1045
110
                const auto count{3 + subs[0].ops.count + subs[1].ops.count + subs[2].ops.count};
1046
110
                const auto sat{(subs[1].ops.sat + subs[0].ops.sat) | (subs[0].ops.dsat + subs[2].ops.sat)};
1047
110
                const auto dsat{subs[0].ops.dsat + subs[2].ops.dsat};
1048
110
                return {count, sat, dsat};
1049
127
            }
1050
49
            case Fragment::MULTI: return {1, (uint32_t)keys.size(), (uint32_t)keys.size()};
1051
5
            case Fragment::MULTI_A: return {(uint32_t)keys.size() + 1, 0, 0};
1052
471
            case Fragment::WRAP_S:
1053
2.19k
            case Fragment::WRAP_C:
1054
2.49k
            case Fragment::WRAP_N: return {1 + subs[0].ops.count, subs[0].ops.sat, subs[0].ops.dsat};
1055
6.96k
            case Fragment::WRAP_A: return {2 + subs[0].ops.count, subs[0].ops.sat, subs[0].ops.dsat};
1056
37
            case Fragment::WRAP_D: return {3 + subs[0].ops.count, subs[0].ops.sat, 0};
1057
16
            case Fragment::WRAP_J: return {4 + subs[0].ops.count, subs[0].ops.sat, 0};
1058
312
            case Fragment::WRAP_V: return {subs[0].ops.count + (subs[0].GetType() << "x"_mst), subs[0].ops.sat, {}};
1059
140
            case Fragment::THRESH: {
1060
140
                uint32_t count = 0;
1061
140
                auto sats = Vector(internal::MaxInt<uint32_t>(0));
1062
679
                for (const auto& sub : subs) {
1063
679
                    count += sub.ops.count + 1;
1064
679
                    auto next_sats = Vector(sats[0] + sub.ops.dsat);
1065
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));
1066
679
                    next_sats.push_back(sats[sats.size() - 1] + sub.ops.sat);
1067
679
                    sats = std::move(next_sats);
1068
679
                }
1069
140
                assert(k < sats.size());
1070
140
                return {count, sats[k], sats[0]};
1071
140
            }
1072
28.2k
        }
1073
28.2k
        assert(false);
1074
0
    }
miniscript::Node<unsigned int>::CalcOps() const
Line
Count
Source
1002
1.72M
    internal::Ops CalcOps() const {
1003
1.72M
        switch (fragment) {
1004
13
            case Fragment::JUST_1: return {0, 0, {}};
1005
260
            case Fragment::JUST_0: return {0, {}, 0};
1006
1.46k
            case Fragment::PK_K: return {0, 0, 0};
1007
489
            case Fragment::PK_H: return {3, 0, 0};
1008
326
            case Fragment::OLDER:
1009
667
            case Fragment::AFTER: return {1, 0, {}};
1010
42
            case Fragment::SHA256:
1011
93
            case Fragment::RIPEMD160:
1012
157
            case Fragment::HASH256:
1013
232
            case Fragment::HASH160: return {4, 0, {}};
1014
732
            case Fragment::AND_V: return {subs[0].ops.count + subs[1].ops.count, subs[0].ops.sat + subs[1].ops.sat, {}};
1015
257
            case Fragment::AND_B: {
1016
257
                const auto count{1 + subs[0].ops.count + subs[1].ops.count};
1017
257
                const auto sat{subs[0].ops.sat + subs[1].ops.sat};
1018
257
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1019
257
                return {count, sat, dsat};
1020
157
            }
1021
64
            case Fragment::OR_B: {
1022
64
                const auto count{1 + subs[0].ops.count + subs[1].ops.count};
1023
64
                const auto sat{(subs[0].ops.sat + subs[1].ops.dsat) | (subs[1].ops.sat + subs[0].ops.dsat)};
1024
64
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1025
64
                return {count, sat, dsat};
1026
157
            }
1027
86
            case Fragment::OR_D: {
1028
86
                const auto count{3 + subs[0].ops.count + subs[1].ops.count};
1029
86
                const auto sat{subs[0].ops.sat | (subs[1].ops.sat + subs[0].ops.dsat)};
1030
86
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1031
86
                return {count, sat, dsat};
1032
157
            }
1033
42
            case Fragment::OR_C: {
1034
42
                const auto count{2 + subs[0].ops.count + subs[1].ops.count};
1035
42
                const auto sat{subs[0].ops.sat | (subs[1].ops.sat + subs[0].ops.dsat)};
1036
42
                return {count, sat, {}};
1037
157
            }
1038
256
            case Fragment::OR_I: {
1039
256
                const auto count{3 + subs[0].ops.count + subs[1].ops.count};
1040
256
                const auto sat{subs[0].ops.sat | subs[1].ops.sat};
1041
256
                const auto dsat{subs[0].ops.dsat | subs[1].ops.dsat};
1042
256
                return {count, sat, dsat};
1043
157
            }
1044
138
            case Fragment::ANDOR: {
1045
138
                const auto count{3 + subs[0].ops.count + subs[1].ops.count + subs[2].ops.count};
1046
138
                const auto sat{(subs[1].ops.sat + subs[0].ops.sat) | (subs[0].ops.dsat + subs[2].ops.sat)};
1047
138
                const auto dsat{subs[0].ops.dsat + subs[2].ops.dsat};
1048
138
                return {count, sat, dsat};
1049
157
            }
1050
128
            case Fragment::MULTI: return {1, (uint32_t)keys.size(), (uint32_t)keys.size()};
1051
32
            case Fragment::MULTI_A: return {(uint32_t)keys.size() + 1, 0, 0};
1052
390
            case Fragment::WRAP_S:
1053
2.32k
            case Fragment::WRAP_C:
1054
1.72M
            case Fragment::WRAP_N: return {1 + subs[0].ops.count, subs[0].ops.sat, subs[0].ops.dsat};
1055
511
            case Fragment::WRAP_A: return {2 + subs[0].ops.count, subs[0].ops.sat, subs[0].ops.dsat};
1056
72
            case Fragment::WRAP_D: return {3 + subs[0].ops.count, subs[0].ops.sat, 0};
1057
0
            case Fragment::WRAP_J: return {4 + subs[0].ops.count, subs[0].ops.sat, 0};
1058
809
            case Fragment::WRAP_V: return {subs[0].ops.count + (subs[0].GetType() << "x"_mst), subs[0].ops.sat, {}};
1059
246
            case Fragment::THRESH: {
1060
246
                uint32_t count = 0;
1061
246
                auto sats = Vector(internal::MaxInt<uint32_t>(0));
1062
828
                for (const auto& sub : subs) {
1063
828
                    count += sub.ops.count + 1;
1064
828
                    auto next_sats = Vector(sats[0] + sub.ops.dsat);
1065
2.16k
                    for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub.ops.dsat) | (sats[j - 1] + sub.ops.sat));
1066
828
                    next_sats.push_back(sats[sats.size() - 1] + sub.ops.sat);
1067
828
                    sats = std::move(next_sats);
1068
828
                }
1069
246
                assert(k < sats.size());
1070
246
                return {count, sats[k], sats[0]};
1071
246
            }
1072
1.72M
        }
1073
1.72M
        assert(false);
1074
0
    }
miniscript::Node<XOnlyPubKey>::CalcOps() const
Line
Count
Source
1002
5.27M
    internal::Ops CalcOps() const {
1003
5.27M
        switch (fragment) {
1004
0
            case Fragment::JUST_1: return {0, 0, {}};
1005
0
            case Fragment::JUST_0: return {0, {}, 0};
1006
2.21k
            case Fragment::PK_K: return {0, 0, 0};
1007
186
            case Fragment::PK_H: return {3, 0, 0};
1008
49
            case Fragment::OLDER:
1009
429
            case Fragment::AFTER: return {1, 0, {}};
1010
0
            case Fragment::SHA256:
1011
0
            case Fragment::RIPEMD160:
1012
12
            case Fragment::HASH256:
1013
12
            case Fragment::HASH160: return {4, 0, {}};
1014
473
            case Fragment::AND_V: return {subs[0].ops.count + subs[1].ops.count, subs[0].ops.sat + subs[1].ops.sat, {}};
1015
48
            case Fragment::AND_B: {
1016
48
                const auto count{1 + subs[0].ops.count + subs[1].ops.count};
1017
48
                const auto sat{subs[0].ops.sat + subs[1].ops.sat};
1018
48
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1019
48
                return {count, sat, dsat};
1020
12
            }
1021
0
            case Fragment::OR_B: {
1022
0
                const auto count{1 + subs[0].ops.count + subs[1].ops.count};
1023
0
                const auto sat{(subs[0].ops.sat + subs[1].ops.dsat) | (subs[1].ops.sat + subs[0].ops.dsat)};
1024
0
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1025
0
                return {count, sat, dsat};
1026
12
            }
1027
0
            case Fragment::OR_D: {
1028
0
                const auto count{3 + subs[0].ops.count + subs[1].ops.count};
1029
0
                const auto sat{subs[0].ops.sat | (subs[1].ops.sat + subs[0].ops.dsat)};
1030
0
                const auto dsat{subs[0].ops.dsat + subs[1].ops.dsat};
1031
0
                return {count, sat, dsat};
1032
12
            }
1033
0
            case Fragment::OR_C: {
1034
0
                const auto count{2 + subs[0].ops.count + subs[1].ops.count};
1035
0
                const auto sat{subs[0].ops.sat | (subs[1].ops.sat + subs[0].ops.dsat)};
1036
0
                return {count, sat, {}};
1037
12
            }
1038
0
            case Fragment::OR_I: {
1039
0
                const auto count{3 + subs[0].ops.count + subs[1].ops.count};
1040
0
                const auto sat{subs[0].ops.sat | subs[1].ops.sat};
1041
0
                const auto dsat{subs[0].ops.dsat | subs[1].ops.dsat};
1042
0
                return {count, sat, dsat};
1043
12
            }
1044
0
            case Fragment::ANDOR: {
1045
0
                const auto count{3 + subs[0].ops.count + subs[1].ops.count + subs[2].ops.count};
1046
0
                const auto sat{(subs[1].ops.sat + subs[0].ops.sat) | (subs[0].ops.dsat + subs[2].ops.sat)};
1047
0
                const auto dsat{subs[0].ops.dsat + subs[2].ops.dsat};
1048
0
                return {count, sat, dsat};
1049
12
            }
1050
0
            case Fragment::MULTI: return {1, (uint32_t)keys.size(), (uint32_t)keys.size()};
1051
771
            case Fragment::MULTI_A: return {(uint32_t)keys.size() + 1, 0, 0};
1052
18
            case Fragment::WRAP_S:
1053
2.41k
            case Fragment::WRAP_C:
1054
5.27M
            case Fragment::WRAP_N: return {1 + subs[0].ops.count, subs[0].ops.sat, subs[0].ops.dsat};
1055
66
            case Fragment::WRAP_A: return {2 + subs[0].ops.count, subs[0].ops.sat, subs[0].ops.dsat};
1056
6
            case Fragment::WRAP_D: return {3 + subs[0].ops.count, subs[0].ops.sat, 0};
1057
0
            case Fragment::WRAP_J: return {4 + subs[0].ops.count, subs[0].ops.sat, 0};
1058
479
            case Fragment::WRAP_V: return {subs[0].ops.count + (subs[0].GetType() << "x"_mst), subs[0].ops.sat, {}};
1059
18
            case Fragment::THRESH: {
1060
18
                uint32_t count = 0;
1061
18
                auto sats = Vector(internal::MaxInt<uint32_t>(0));
1062
54
                for (const auto& sub : subs) {
1063
54
                    count += sub.ops.count + 1;
1064
54
                    auto next_sats = Vector(sats[0] + sub.ops.dsat);
1065
108
                    for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub.ops.dsat) | (sats[j - 1] + sub.ops.sat));
1066
54
                    next_sats.push_back(sats[sats.size() - 1] + sub.ops.sat);
1067
54
                    sats = std::move(next_sats);
1068
54
                }
1069
18
                assert(k < sats.size());
1070
18
                return {count, sats[k], sats[0]};
1071
18
            }
1072
5.27M
        }
1073
5.27M
        assert(false);
1074
0
    }
1075
1076
7.03M
    internal::StackSize CalcStackSize() const {
1077
7.03M
        using namespace internal;
1078
7.03M
        switch (fragment) {
1079
709
            case Fragment::JUST_0: return {{}, SatInfo::Push()};
1080
245
            case Fragment::JUST_1: return {SatInfo::Push(), {}};
1081
7.95k
            case Fragment::OLDER:
1082
9.05k
            case Fragment::AFTER: return {SatInfo::Push() + SatInfo::Nop(), {}};
1083
5.35k
            case Fragment::PK_K: return {SatInfo::Push()};
1084
775
            case Fragment::PK_H: return {SatInfo::OP_DUP() + SatInfo::Hash() + SatInfo::Push() + SatInfo::OP_EQUALVERIFY()};
1085
103
            case Fragment::SHA256:
1086
180
            case Fragment::RIPEMD160:
1087
296
            case Fragment::HASH256:
1088
395
            case Fragment::HASH160: return {
1089
395
                SatInfo::OP_SIZE() + SatInfo::Push() + SatInfo::OP_EQUALVERIFY() + SatInfo::Hash() + SatInfo::Push() + SatInfo::OP_EQUAL(),
1090
395
                {}
1091
395
            };
1092
248
            case Fragment::ANDOR: {
1093
248
                const auto& x{subs[0].ss};
1094
248
                const auto& y{subs[1].ss};
1095
248
                const auto& z{subs[2].ss};
1096
248
                return {
1097
248
                    (x.Sat() + SatInfo::If() + y.Sat()) | (x.Dsat() + SatInfo::If() + z.Sat()),
1098
248
                    x.Dsat() + SatInfo::If() + z.Dsat()
1099
248
                };
1100
296
            }
1101
1.46k
            case Fragment::AND_V: {
1102
1.46k
                const auto& x{subs[0].ss};
1103
1.46k
                const auto& y{subs[1].ss};
1104
1.46k
                return {x.Sat() + y.Sat(), {}};
1105
296
            }
1106
7.15k
            case Fragment::AND_B: {
1107
7.15k
                const auto& x{subs[0].ss};
1108
7.15k
                const auto& y{subs[1].ss};
1109
7.15k
                return {x.Sat() + y.Sat() + SatInfo::BinaryOp(), x.Dsat() + y.Dsat() + SatInfo::BinaryOp()};
1110
296
            }
1111
93
            case Fragment::OR_B: {
1112
93
                const auto& x{subs[0].ss};
1113
93
                const auto& y{subs[1].ss};
1114
93
                return {
1115
93
                    ((x.Sat() + y.Dsat()) | (x.Dsat() + y.Sat())) + SatInfo::BinaryOp(),
1116
93
                    x.Dsat() + y.Dsat() + SatInfo::BinaryOp()
1117
93
                };
1118
296
            }
1119
62
            case Fragment::OR_C: {
1120
62
                const auto& x{subs[0].ss};
1121
62
                const auto& y{subs[1].ss};
1122
62
                return {(x.Sat() + SatInfo::If()) | (x.Dsat() + SatInfo::If() + y.Sat()), {}};
1123
296
            }
1124
132
            case Fragment::OR_D: {
1125
132
                const auto& x{subs[0].ss};
1126
132
                const auto& y{subs[1].ss};
1127
132
                return {
1128
132
                    (x.Sat() + SatInfo::OP_IFDUP(true) + SatInfo::If()) | (x.Dsat() + SatInfo::OP_IFDUP(false) + SatInfo::If() + y.Sat()),
1129
132
                    x.Dsat() + SatInfo::OP_IFDUP(false) + SatInfo::If() + y.Dsat()
1130
132
                };
1131
296
            }
1132
647
            case Fragment::OR_I: {
1133
647
                const auto& x{subs[0].ss};
1134
647
                const auto& y{subs[1].ss};
1135
647
                return {SatInfo::If() + (x.Sat() | y.Sat()), SatInfo::If() + (x.Dsat() | y.Dsat())};
1136
296
            }
1137
            // multi(k, key1, key2, ..., key_n) starts off with k+1 stack elements (a 0, plus k
1138
            // signatures), then reaches n+k+3 stack elements after pushing the n keys, plus k and
1139
            // n itself, and ends with 1 stack element (success or failure). Thus, it net removes
1140
            // k elements (from k+1 to 1), while reaching k+n+2 more than it ends with.
1141
177
            case Fragment::MULTI: return {SatInfo(k, k + keys.size() + 2)};
1142
            // multi_a(k, key1, key2, ..., key_n) starts off with n stack elements (the
1143
            // signatures), reaches 1 more (after the first key push), and ends with 1. Thus it net
1144
            // removes n-1 elements (from n to 1) while reaching n more than it ends with.
1145
808
            case Fragment::MULTI_A: return {SatInfo(keys.size() - 1, keys.size())};
1146
7.54k
            case Fragment::WRAP_A:
1147
6.99M
            case Fragment::WRAP_N:
1148
6.99M
            case Fragment::WRAP_S: return subs[0].ss;
1149
6.05k
            case Fragment::WRAP_C: return {
1150
6.05k
                subs[0].ss.Sat() + SatInfo::OP_CHECKSIG(),
1151
6.05k
                subs[0].ss.Dsat() + SatInfo::OP_CHECKSIG()
1152
6.05k
            };
1153
115
            case Fragment::WRAP_D: return {
1154
115
                SatInfo::OP_DUP() + SatInfo::If() + subs[0].ss.Sat(),
1155
115
                SatInfo::OP_DUP() + SatInfo::If()
1156
115
            };
1157
1.60k
            case Fragment::WRAP_V: return {subs[0].ss.Sat() + SatInfo::OP_VERIFY(), {}};
1158
16
            case Fragment::WRAP_J: return {
1159
16
                SatInfo::OP_SIZE() + SatInfo::OP_0NOTEQUAL() + SatInfo::If() + subs[0].ss.Sat(),
1160
16
                SatInfo::OP_SIZE() + SatInfo::OP_0NOTEQUAL() + SatInfo::If()
1161
16
            };
1162
404
            case Fragment::THRESH: {
1163
                // sats[j] is the SatInfo corresponding to all traces reaching j satisfactions.
1164
404
                auto sats = Vector(SatInfo::Empty());
1165
1.96k
                for (size_t i = 0; i < subs.size(); ++i) {
1166
                    // Loop over the subexpressions, processing them one by one. After adding
1167
                    // element i we need to add OP_ADD (if i>0).
1168
1.56k
                    auto add = i ? SatInfo::BinaryOp() : SatInfo::Empty();
1169
                    // Construct a variable that will become the next sats, starting with index 0.
1170
1.56k
                    auto next_sats = Vector(sats[0] + subs[i].ss.Dsat() + add);
1171
                    // Then loop to construct next_sats[1..i].
1172
4.62k
                    for (size_t j = 1; j < sats.size(); ++j) {
1173
3.05k
                        next_sats.push_back(((sats[j] + subs[i].ss.Dsat()) | (sats[j - 1] + subs[i].ss.Sat())) + add);
1174
3.05k
                    }
1175
                    // Finally construct next_sats[i+1].
1176
1.56k
                    next_sats.push_back(sats[sats.size() - 1] + subs[i].ss.Sat() + add);
1177
                    // Switch over.
1178
1.56k
                    sats = std::move(next_sats);
1179
1.56k
                }
1180
                // To satisfy thresh we need k satisfactions; to dissatisfy we need 0. In both
1181
                // cases a push of k and an OP_EQUAL follow.
1182
404
                return {
1183
404
                    sats[k] + SatInfo::Push() + SatInfo::OP_EQUAL(),
1184
404
                    sats[0] + SatInfo::Push() + SatInfo::OP_EQUAL()
1185
404
                };
1186
6.99M
            }
1187
7.03M
        }
1188
7.03M
        assert(false);
1189
0
    }
miniscript::Node<CPubKey>::CalcStackSize() const
Line
Count
Source
1076
28.2k
    internal::StackSize CalcStackSize() const {
1077
28.2k
        using namespace internal;
1078
28.2k
        switch (fragment) {
1079
449
            case Fragment::JUST_0: return {{}, SatInfo::Push()};
1080
232
            case Fragment::JUST_1: return {SatInfo::Push(), {}};
1081
7.57k
            case Fragment::OLDER:
1082
7.95k
            case Fragment::AFTER: return {SatInfo::Push() + SatInfo::Nop(), {}};
1083
1.67k
            case Fragment::PK_K: return {SatInfo::Push()};
1084
100
            case Fragment::PK_H: return {SatInfo::OP_DUP() + SatInfo::Hash() + SatInfo::Push() + SatInfo::OP_EQUALVERIFY()};
1085
61
            case Fragment::SHA256:
1086
87
            case Fragment::RIPEMD160:
1087
127
            case Fragment::HASH256:
1088
151
            case Fragment::HASH160: return {
1089
151
                SatInfo::OP_SIZE() + SatInfo::Push() + SatInfo::OP_EQUALVERIFY() + SatInfo::Hash() + SatInfo::Push() + SatInfo::OP_EQUAL(),
1090
151
                {}
1091
151
            };
1092
110
            case Fragment::ANDOR: {
1093
110
                const auto& x{subs[0].ss};
1094
110
                const auto& y{subs[1].ss};
1095
110
                const auto& z{subs[2].ss};
1096
110
                return {
1097
110
                    (x.Sat() + SatInfo::If() + y.Sat()) | (x.Dsat() + SatInfo::If() + z.Sat()),
1098
110
                    x.Dsat() + SatInfo::If() + z.Dsat()
1099
110
                };
1100
127
            }
1101
255
            case Fragment::AND_V: {
1102
255
                const auto& x{subs[0].ss};
1103
255
                const auto& y{subs[1].ss};
1104
255
                return {x.Sat() + y.Sat(), {}};
1105
127
            }
1106
6.85k
            case Fragment::AND_B: {
1107
6.85k
                const auto& x{subs[0].ss};
1108
6.85k
                const auto& y{subs[1].ss};
1109
6.85k
                return {x.Sat() + y.Sat() + SatInfo::BinaryOp(), x.Dsat() + y.Dsat() + SatInfo::BinaryOp()};
1110
127
            }
1111
29
            case Fragment::OR_B: {
1112
29
                const auto& x{subs[0].ss};
1113
29
                const auto& y{subs[1].ss};
1114
29
                return {
1115
29
                    ((x.Sat() + y.Dsat()) | (x.Dsat() + y.Sat())) + SatInfo::BinaryOp(),
1116
29
                    x.Dsat() + y.Dsat() + SatInfo::BinaryOp()
1117
29
                };
1118
127
            }
1119
20
            case Fragment::OR_C: {
1120
20
                const auto& x{subs[0].ss};
1121
20
                const auto& y{subs[1].ss};
1122
20
                return {(x.Sat() + SatInfo::If()) | (x.Dsat() + SatInfo::If() + y.Sat()), {}};
1123
127
            }
1124
46
            case Fragment::OR_D: {
1125
46
                const auto& x{subs[0].ss};
1126
46
                const auto& y{subs[1].ss};
1127
46
                return {
1128
46
                    (x.Sat() + SatInfo::OP_IFDUP(true) + SatInfo::If()) | (x.Dsat() + SatInfo::OP_IFDUP(false) + SatInfo::If() + y.Sat()),
1129
46
                    x.Dsat() + SatInfo::OP_IFDUP(false) + SatInfo::If() + y.Dsat()
1130
46
                };
1131
127
            }
1132
391
            case Fragment::OR_I: {
1133
391
                const auto& x{subs[0].ss};
1134
391
                const auto& y{subs[1].ss};
1135
391
                return {SatInfo::If() + (x.Sat() | y.Sat()), SatInfo::If() + (x.Dsat() | y.Dsat())};
1136
127
            }
1137
            // multi(k, key1, key2, ..., key_n) starts off with k+1 stack elements (a 0, plus k
1138
            // signatures), then reaches n+k+3 stack elements after pushing the n keys, plus k and
1139
            // n itself, and ends with 1 stack element (success or failure). Thus, it net removes
1140
            // k elements (from k+1 to 1), while reaching k+n+2 more than it ends with.
1141
49
            case Fragment::MULTI: return {SatInfo(k, k + keys.size() + 2)};
1142
            // multi_a(k, key1, key2, ..., key_n) starts off with n stack elements (the
1143
            // signatures), reaches 1 more (after the first key push), and ends with 1. Thus it net
1144
            // removes n-1 elements (from n to 1) while reaching n more than it ends with.
1145
5
            case Fragment::MULTI_A: return {SatInfo(keys.size() - 1, keys.size())};
1146
6.96k
            case Fragment::WRAP_A:
1147
7.26k
            case Fragment::WRAP_N:
1148
7.73k
            case Fragment::WRAP_S: return subs[0].ss;
1149
1.72k
            case Fragment::WRAP_C: return {
1150
1.72k
                subs[0].ss.Sat() + SatInfo::OP_CHECKSIG(),
1151
1.72k
                subs[0].ss.Dsat() + SatInfo::OP_CHECKSIG()
1152
1.72k
            };
1153
37
            case Fragment::WRAP_D: return {
1154
37
                SatInfo::OP_DUP() + SatInfo::If() + subs[0].ss.Sat(),
1155
37
                SatInfo::OP_DUP() + SatInfo::If()
1156
37
            };
1157
312
            case Fragment::WRAP_V: return {subs[0].ss.Sat() + SatInfo::OP_VERIFY(), {}};
1158
16
            case Fragment::WRAP_J: return {
1159
16
                SatInfo::OP_SIZE() + SatInfo::OP_0NOTEQUAL() + SatInfo::If() + subs[0].ss.Sat(),
1160
16
                SatInfo::OP_SIZE() + SatInfo::OP_0NOTEQUAL() + SatInfo::If()
1161
16
            };
1162
140
            case Fragment::THRESH: {
1163
                // sats[j] is the SatInfo corresponding to all traces reaching j satisfactions.
1164
140
                auto sats = Vector(SatInfo::Empty());
1165
819
                for (size_t i = 0; i < subs.size(); ++i) {
1166
                    // Loop over the subexpressions, processing them one by one. After adding
1167
                    // element i we need to add OP_ADD (if i>0).
1168
679
                    auto add = i ? SatInfo::BinaryOp() : SatInfo::Empty();
1169
                    // Construct a variable that will become the next sats, starting with index 0.
1170
679
                    auto next_sats = Vector(sats[0] + subs[i].ss.Dsat() + add);
1171
                    // Then loop to construct next_sats[1..i].
1172
2.35k
                    for (size_t j = 1; j < sats.size(); ++j) {
1173
1.67k
                        next_sats.push_back(((sats[j] + subs[i].ss.Dsat()) | (sats[j - 1] + subs[i].ss.Sat())) + add);
1174
1.67k
                    }
1175
                    // Finally construct next_sats[i+1].
1176
679
                    next_sats.push_back(sats[sats.size() - 1] + subs[i].ss.Sat() + add);
1177
                    // Switch over.
1178
679
                    sats = std::move(next_sats);
1179
679
                }
1180
                // To satisfy thresh we need k satisfactions; to dissatisfy we need 0. In both
1181
                // cases a push of k and an OP_EQUAL follow.
1182
140
                return {
1183
140
                    sats[k] + SatInfo::Push() + SatInfo::OP_EQUAL(),
1184
140
                    sats[0] + SatInfo::Push() + SatInfo::OP_EQUAL()
1185
140
                };
1186
7.26k
            }
1187
28.2k
        }
1188
28.2k
        assert(false);
1189
0
    }
miniscript::Node<unsigned int>::CalcStackSize() const
Line
Count
Source
1076
1.72M
    internal::StackSize CalcStackSize() const {
1077
1.72M
        using namespace internal;
1078
1.72M
        switch (fragment) {
1079
260
            case Fragment::JUST_0: return {{}, SatInfo::Push()};
1080
13
            case Fragment::JUST_1: return {SatInfo::Push(), {}};
1081
326
            case Fragment::OLDER:
1082
667
            case Fragment::AFTER: return {SatInfo::Push() + SatInfo::Nop(), {}};
1083
1.46k
            case Fragment::PK_K: return {SatInfo::Push()};
1084
489
            case Fragment::PK_H: return {SatInfo::OP_DUP() + SatInfo::Hash() + SatInfo::Push() + SatInfo::OP_EQUALVERIFY()};
1085
42
            case Fragment::SHA256:
1086
93
            case Fragment::RIPEMD160:
1087
157
            case Fragment::HASH256:
1088
232
            case Fragment::HASH160: return {
1089
232
                SatInfo::OP_SIZE() + SatInfo::Push() + SatInfo::OP_EQUALVERIFY() + SatInfo::Hash() + SatInfo::Push() + SatInfo::OP_EQUAL(),
1090
232
                {}
1091
232
            };
1092
138
            case Fragment::ANDOR: {
1093
138
                const auto& x{subs[0].ss};
1094
138
                const auto& y{subs[1].ss};
1095
138
                const auto& z{subs[2].ss};
1096
138
                return {
1097
138
                    (x.Sat() + SatInfo::If() + y.Sat()) | (x.Dsat() + SatInfo::If() + z.Sat()),
1098
138
                    x.Dsat() + SatInfo::If() + z.Dsat()
1099
138
                };
1100
157
            }
1101
732
            case Fragment::AND_V: {
1102
732
                const auto& x{subs[0].ss};
1103
732
                const auto& y{subs[1].ss};
1104
732
                return {x.Sat() + y.Sat(), {}};
1105
157
            }
1106
257
            case Fragment::AND_B: {
1107
257
                const auto& x{subs[0].ss};
1108
257
                const auto& y{subs[1].ss};
1109
257
                return {x.Sat() + y.Sat() + SatInfo::BinaryOp(), x.Dsat() + y.Dsat() + SatInfo::BinaryOp()};
1110
157
            }
1111
64
            case Fragment::OR_B: {
1112
64
                const auto& x{subs[0].ss};
1113
64
                const auto& y{subs[1].ss};
1114
64
                return {
1115
64
                    ((x.Sat() + y.Dsat()) | (x.Dsat() + y.Sat())) + SatInfo::BinaryOp(),
1116
64
                    x.Dsat() + y.Dsat() + SatInfo::BinaryOp()
1117
64
                };
1118
157
            }
1119
42
            case Fragment::OR_C: {
1120
42
                const auto& x{subs[0].ss};
1121
42
                const auto& y{subs[1].ss};
1122
42
                return {(x.Sat() + SatInfo::If()) | (x.Dsat() + SatInfo::If() + y.Sat()), {}};
1123
157
            }
1124
86
            case Fragment::OR_D: {
1125
86
                const auto& x{subs[0].ss};
1126
86
                const auto& y{subs[1].ss};
1127
86
                return {
1128
86
                    (x.Sat() + SatInfo::OP_IFDUP(true) + SatInfo::If()) | (x.Dsat() + SatInfo::OP_IFDUP(false) + SatInfo::If() + y.Sat()),
1129
86
                    x.Dsat() + SatInfo::OP_IFDUP(false) + SatInfo::If() + y.Dsat()
1130
86
                };
1131
157
            }
1132
256
            case Fragment::OR_I: {
1133
256
                const auto& x{subs[0].ss};
1134
256
                const auto& y{subs[1].ss};
1135
256
                return {SatInfo::If() + (x.Sat() | y.Sat()), SatInfo::If() + (x.Dsat() | y.Dsat())};
1136
157
            }
1137
            // multi(k, key1, key2, ..., key_n) starts off with k+1 stack elements (a 0, plus k
1138
            // signatures), then reaches n+k+3 stack elements after pushing the n keys, plus k and
1139
            // n itself, and ends with 1 stack element (success or failure). Thus, it net removes
1140
            // k elements (from k+1 to 1), while reaching k+n+2 more than it ends with.
1141
128
            case Fragment::MULTI: return {SatInfo(k, k + keys.size() + 2)};
1142
            // multi_a(k, key1, key2, ..., key_n) starts off with n stack elements (the
1143
            // signatures), reaches 1 more (after the first key push), and ends with 1. Thus it net
1144
            // removes n-1 elements (from n to 1) while reaching n more than it ends with.
1145
32
            case Fragment::MULTI_A: return {SatInfo(keys.size() - 1, keys.size())};
1146
511
            case Fragment::WRAP_A:
1147
1.71M
            case Fragment::WRAP_N:
1148
1.71M
            case Fragment::WRAP_S: return subs[0].ss;
1149
1.93k
            case Fragment::WRAP_C: return {
1150
1.93k
                subs[0].ss.Sat() + SatInfo::OP_CHECKSIG(),
1151
1.93k
                subs[0].ss.Dsat() + SatInfo::OP_CHECKSIG()
1152
1.93k
            };
1153
72
            case Fragment::WRAP_D: return {
1154
72
                SatInfo::OP_DUP() + SatInfo::If() + subs[0].ss.Sat(),
1155
72
                SatInfo::OP_DUP() + SatInfo::If()
1156
72
            };
1157
809
            case Fragment::WRAP_V: return {subs[0].ss.Sat() + SatInfo::OP_VERIFY(), {}};
1158
0
            case Fragment::WRAP_J: return {
1159
0
                SatInfo::OP_SIZE() + SatInfo::OP_0NOTEQUAL() + SatInfo::If() + subs[0].ss.Sat(),
1160
0
                SatInfo::OP_SIZE() + SatInfo::OP_0NOTEQUAL() + SatInfo::If()
1161
0
            };
1162
246
            case Fragment::THRESH: {
1163
                // sats[j] is the SatInfo corresponding to all traces reaching j satisfactions.
1164
246
                auto sats = Vector(SatInfo::Empty());
1165
1.07k
                for (size_t i = 0; i < subs.size(); ++i) {
1166
                    // Loop over the subexpressions, processing them one by one. After adding
1167
                    // element i we need to add OP_ADD (if i>0).
1168
828
                    auto add = i ? SatInfo::BinaryOp() : SatInfo::Empty();
1169
                    // Construct a variable that will become the next sats, starting with index 0.
1170
828
                    auto next_sats = Vector(sats[0] + subs[i].ss.Dsat() + add);
1171
                    // Then loop to construct next_sats[1..i].
1172
2.16k
                    for (size_t j = 1; j < sats.size(); ++j) {
1173
1.33k
                        next_sats.push_back(((sats[j] + subs[i].ss.Dsat()) | (sats[j - 1] + subs[i].ss.Sat())) + add);
1174
1.33k
                    }
1175
                    // Finally construct next_sats[i+1].
1176
828
                    next_sats.push_back(sats[sats.size() - 1] + subs[i].ss.Sat() + add);
1177
                    // Switch over.
1178
828
                    sats = std::move(next_sats);
1179
828
                }
1180
                // To satisfy thresh we need k satisfactions; to dissatisfy we need 0. In both
1181
                // cases a push of k and an OP_EQUAL follow.
1182
246
                return {
1183
246
                    sats[k] + SatInfo::Push() + SatInfo::OP_EQUAL(),
1184
246
                    sats[0] + SatInfo::Push() + SatInfo::OP_EQUAL()
1185
246
                };
1186
1.71M
            }
1187
1.72M
        }
1188
1.72M
        assert(false);
1189
0
    }
miniscript::Node<XOnlyPubKey>::CalcStackSize() const
Line
Count
Source
1076
5.27M
    internal::StackSize CalcStackSize() const {
1077
5.27M
        using namespace internal;
1078
5.27M
        switch (fragment) {
1079
0
            case Fragment::JUST_0: return {{}, SatInfo::Push()};
1080
0
            case Fragment::JUST_1: return {SatInfo::Push(), {}};
1081
49
            case Fragment::OLDER:
1082
429
            case Fragment::AFTER: return {SatInfo::Push() + SatInfo::Nop(), {}};
1083
2.21k
            case Fragment::PK_K: return {SatInfo::Push()};
1084
186
            case Fragment::PK_H: return {SatInfo::OP_DUP() + SatInfo::Hash() + SatInfo::Push() + SatInfo::OP_EQUALVERIFY()};
1085
0
            case Fragment::SHA256:
1086
0
            case Fragment::RIPEMD160:
1087
12
            case Fragment::HASH256:
1088
12
            case Fragment::HASH160: return {
1089
12
                SatInfo::OP_SIZE() + SatInfo::Push() + SatInfo::OP_EQUALVERIFY() + SatInfo::Hash() + SatInfo::Push() + SatInfo::OP_EQUAL(),
1090
12
                {}
1091
12
            };
1092
0
            case Fragment::ANDOR: {
1093
0
                const auto& x{subs[0].ss};
1094
0
                const auto& y{subs[1].ss};
1095
0
                const auto& z{subs[2].ss};
1096
0
                return {
1097
0
                    (x.Sat() + SatInfo::If() + y.Sat()) | (x.Dsat() + SatInfo::If() + z.Sat()),
1098
0
                    x.Dsat() + SatInfo::If() + z.Dsat()
1099
0
                };
1100
12
            }
1101
473
            case Fragment::AND_V: {
1102
473
                const auto& x{subs[0].ss};
1103
473
                const auto& y{subs[1].ss};
1104
473
                return {x.Sat() + y.Sat(), {}};
1105
12
            }
1106
48
            case Fragment::AND_B: {
1107
48
                const auto& x{subs[0].ss};
1108
48
                const auto& y{subs[1].ss};
1109
48
                return {x.Sat() + y.Sat() + SatInfo::BinaryOp(), x.Dsat() + y.Dsat() + SatInfo::BinaryOp()};
1110
12
            }
1111
0
            case Fragment::OR_B: {
1112
0
                const auto& x{subs[0].ss};
1113
0
                const auto& y{subs[1].ss};
1114
0
                return {
1115
0
                    ((x.Sat() + y.Dsat()) | (x.Dsat() + y.Sat())) + SatInfo::BinaryOp(),
1116
0
                    x.Dsat() + y.Dsat() + SatInfo::BinaryOp()
1117
0
                };
1118
12
            }
1119
0
            case Fragment::OR_C: {
1120
0
                const auto& x{subs[0].ss};
1121
0
                const auto& y{subs[1].ss};
1122
0
                return {(x.Sat() + SatInfo::If()) | (x.Dsat() + SatInfo::If() + y.Sat()), {}};
1123
12
            }
1124
0
            case Fragment::OR_D: {
1125
0
                const auto& x{subs[0].ss};
1126
0
                const auto& y{subs[1].ss};
1127
0
                return {
1128
0
                    (x.Sat() + SatInfo::OP_IFDUP(true) + SatInfo::If()) | (x.Dsat() + SatInfo::OP_IFDUP(false) + SatInfo::If() + y.Sat()),
1129
0
                    x.Dsat() + SatInfo::OP_IFDUP(false) + SatInfo::If() + y.Dsat()
1130
0
                };
1131
12
            }
1132
0
            case Fragment::OR_I: {
1133
0
                const auto& x{subs[0].ss};
1134
0
                const auto& y{subs[1].ss};
1135
0
                return {SatInfo::If() + (x.Sat() | y.Sat()), SatInfo::If() + (x.Dsat() | y.Dsat())};
1136
12
            }
1137
            // multi(k, key1, key2, ..., key_n) starts off with k+1 stack elements (a 0, plus k
1138
            // signatures), then reaches n+k+3 stack elements after pushing the n keys, plus k and
1139
            // n itself, and ends with 1 stack element (success or failure). Thus, it net removes
1140
            // k elements (from k+1 to 1), while reaching k+n+2 more than it ends with.
1141
0
            case Fragment::MULTI: return {SatInfo(k, k + keys.size() + 2)};
1142
            // multi_a(k, key1, key2, ..., key_n) starts off with n stack elements (the
1143
            // signatures), reaches 1 more (after the first key push), and ends with 1. Thus it net
1144
            // removes n-1 elements (from n to 1) while reaching n more than it ends with.
1145
771
            case Fragment::MULTI_A: return {SatInfo(keys.size() - 1, keys.size())};
1146
66
            case Fragment::WRAP_A:
1147
5.27M
            case Fragment::WRAP_N:
1148
5.27M
            case Fragment::WRAP_S: return subs[0].ss;
1149
2.40k
            case Fragment::WRAP_C: return {
1150
2.40k
                subs[0].ss.Sat() + SatInfo::OP_CHECKSIG(),
1151
2.40k
                subs[0].ss.Dsat() + SatInfo::OP_CHECKSIG()
1152
2.40k
            };
1153
6
            case Fragment::WRAP_D: return {
1154
6
                SatInfo::OP_DUP() + SatInfo::If() + subs[0].ss.Sat(),
1155
6
                SatInfo::OP_DUP() + SatInfo::If()
1156
6
            };
1157
479
            case Fragment::WRAP_V: return {subs[0].ss.Sat() + SatInfo::OP_VERIFY(), {}};
1158
0
            case Fragment::WRAP_J: return {
1159
0
                SatInfo::OP_SIZE() + SatInfo::OP_0NOTEQUAL() + SatInfo::If() + subs[0].ss.Sat(),
1160
0
                SatInfo::OP_SIZE() + SatInfo::OP_0NOTEQUAL() + SatInfo::If()
1161
0
            };
1162
18
            case Fragment::THRESH: {
1163
                // sats[j] is the SatInfo corresponding to all traces reaching j satisfactions.
1164
18
                auto sats = Vector(SatInfo::Empty());
1165
72
                for (size_t i = 0; i < subs.size(); ++i) {
1166
                    // Loop over the subexpressions, processing them one by one. After adding
1167
                    // element i we need to add OP_ADD (if i>0).
1168
54
                    auto add = i ? SatInfo::BinaryOp() : SatInfo::Empty();
1169
                    // Construct a variable that will become the next sats, starting with index 0.
1170
54
                    auto next_sats = Vector(sats[0] + subs[i].ss.Dsat() + add);
1171
                    // Then loop to construct next_sats[1..i].
1172
108
                    for (size_t j = 1; j < sats.size(); ++j) {
1173
54
                        next_sats.push_back(((sats[j] + subs[i].ss.Dsat()) | (sats[j - 1] + subs[i].ss.Sat())) + add);
1174
54
                    }
1175
                    // Finally construct next_sats[i+1].
1176
54
                    next_sats.push_back(sats[sats.size() - 1] + subs[i].ss.Sat() + add);
1177
                    // Switch over.
1178
54
                    sats = std::move(next_sats);
1179
54
                }
1180
                // To satisfy thresh we need k satisfactions; to dissatisfy we need 0. In both
1181
                // cases a push of k and an OP_EQUAL follow.
1182
18
                return {
1183
18
                    sats[k] + SatInfo::Push() + SatInfo::OP_EQUAL(),
1184
18
                    sats[0] + SatInfo::Push() + SatInfo::OP_EQUAL()
1185
18
                };
1186
5.27M
            }
1187
5.27M
        }
1188
5.27M
        assert(false);
1189
0
    }
1190
1191
7.03M
    internal::WitnessSize CalcWitnessSize() const {
1192
7.03M
        const uint32_t sig_size = IsTapscript(m_script_ctx) ? 1 + 65 : 1 + 72;
1193
7.03M
        const uint32_t pubkey_size = IsTapscript(m_script_ctx) ? 1 + 32 : 1 + 33;
1194
7.03M
        switch (fragment) {
1195
709
            case Fragment::JUST_0: return {{}, 0};
1196
245
            case Fragment::JUST_1:
1197
8.19k
            case Fragment::OLDER:
1198
9.29k
            case Fragment::AFTER: return {0, {}};
1199
5.35k
            case Fragment::PK_K: return {sig_size, 1};
1200
775
            case Fragment::PK_H: return {sig_size + pubkey_size, 1 + pubkey_size};
1201
103
            case Fragment::SHA256:
1202
180
            case Fragment::RIPEMD160:
1203
296
            case Fragment::HASH256:
1204
395
            case Fragment::HASH160: return {1 + 32, {}};
1205
248
            case Fragment::ANDOR: {
1206
248
                const auto sat{(subs[0].ws.sat + subs[1].ws.sat) | (subs[0].ws.dsat + subs[2].ws.sat)};
1207
248
                const auto dsat{subs[0].ws.dsat + subs[2].ws.dsat};
1208
248
                return {sat, dsat};
1209
296
            }
1210
1.46k
            case Fragment::AND_V: return {subs[0].ws.sat + subs[1].ws.sat, {}};
1211
7.15k
            case Fragment::AND_B: return {subs[0].ws.sat + subs[1].ws.sat, subs[0].ws.dsat + subs[1].ws.dsat};
1212
93
            case Fragment::OR_B: {
1213
93
                const auto sat{(subs[0].ws.dsat + subs[1].ws.sat) | (subs[0].ws.sat + subs[1].ws.dsat)};
1214
93
                const auto dsat{subs[0].ws.dsat + subs[1].ws.dsat};
1215
93
                return {sat, dsat};
1216
296
            }
1217
62
            case Fragment::OR_C: return {subs[0].ws.sat | (subs[0].ws.dsat + subs[1].ws.sat), {}};
1218
132
            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};
1219
647
            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)};
1220
177
            case Fragment::MULTI: return {k * sig_size + 1, k + 1};
1221
808
            case Fragment::MULTI_A: return {k * sig_size + static_cast<uint32_t>(keys.size()) - k, static_cast<uint32_t>(keys.size())};
1222
7.54k
            case Fragment::WRAP_A:
1223
6.99M
            case Fragment::WRAP_N:
1224
6.99M
            case Fragment::WRAP_S:
1225
7.00M
            case Fragment::WRAP_C: return subs[0].ws;
1226
115
            case Fragment::WRAP_D: return {1 + 1 + subs[0].ws.sat, 1};
1227
1.60k
            case Fragment::WRAP_V: return {subs[0].ws.sat, {}};
1228
16
            case Fragment::WRAP_J: return {subs[0].ws.sat, 1};
1229
404
            case Fragment::THRESH: {
1230
404
                auto sats = Vector(internal::MaxInt<uint32_t>(0));
1231
1.56k
                for (const auto& sub : subs) {
1232
1.56k
                    auto next_sats = Vector(sats[0] + sub.ws.dsat);
1233
4.62k
                    for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub.ws.dsat) | (sats[j - 1] + sub.ws.sat));
1234
1.56k
                    next_sats.push_back(sats[sats.size() - 1] + sub.ws.sat);
1235
1.56k
                    sats = std::move(next_sats);
1236
1.56k
                }
1237
404
                assert(k < sats.size());
1238
404
                return {sats[k], sats[0]};
1239
404
            }
1240
7.03M
        }
1241
7.03M
        assert(false);
1242
0
    }
miniscript::Node<CPubKey>::CalcWitnessSize() const
Line
Count
Source
1191
28.2k
    internal::WitnessSize CalcWitnessSize() const {
1192
28.2k
        const uint32_t sig_size = IsTapscript(m_script_ctx) ? 1 + 65 : 1 + 72;
1193
28.2k
        const uint32_t pubkey_size = IsTapscript(m_script_ctx) ? 1 + 32 : 1 + 33;
1194
28.2k
        switch (fragment) {
1195
449
            case Fragment::JUST_0: return {{}, 0};
1196
232
            case Fragment::JUST_1:
1197
7.80k
            case Fragment::OLDER:
1198
8.19k
            case Fragment::AFTER: return {0, {}};
1199
1.67k
            case Fragment::PK_K: return {sig_size, 1};
1200
100
            case Fragment::PK_H: return {sig_size + pubkey_size, 1 + pubkey_size};
1201
61
            case Fragment::SHA256:
1202
87
            case Fragment::RIPEMD160:
1203
127
            case Fragment::HASH256:
1204
151
            case Fragment::HASH160: return {1 + 32, {}};
1205
110
            case Fragment::ANDOR: {
1206
110
                const auto sat{(subs[0].ws.sat + subs[1].ws.sat) | (subs[0].ws.dsat + subs[2].ws.sat)};
1207
110
                const auto dsat{subs[0].ws.dsat + subs[2].ws.dsat};
1208
110
                return {sat, dsat};
1209
127
            }
1210
255
            case Fragment::AND_V: return {subs[0].ws.sat + subs[1].ws.sat, {}};
1211
6.85k
            case Fragment::AND_B: return {subs[0].ws.sat + subs[1].ws.sat, subs[0].ws.dsat + subs[1].ws.dsat};
1212
29
            case Fragment::OR_B: {
1213
29
                const auto sat{(subs[0].ws.dsat + subs[1].ws.sat) | (subs[0].ws.sat + subs[1].ws.dsat)};
1214
29
                const auto dsat{subs[0].ws.dsat + subs[1].ws.dsat};
1215
29
                return {sat, dsat};
1216
127
            }
1217
20
            case Fragment::OR_C: return {subs[0].ws.sat | (subs[0].ws.dsat + subs[1].ws.sat), {}};
1218
46
            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};
1219
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)};
1220
49
            case Fragment::MULTI: return {k * sig_size + 1, k + 1};
1221
5
            case Fragment::MULTI_A: return {k * sig_size + static_cast<uint32_t>(keys.size()) - k, static_cast<uint32_t>(keys.size())};
1222
6.96k
            case Fragment::WRAP_A:
1223
7.26k
            case Fragment::WRAP_N:
1224
7.73k
            case Fragment::WRAP_S:
1225
9.46k
            case Fragment::WRAP_C: return subs[0].ws;
1226
37
            case Fragment::WRAP_D: return {1 + 1 + subs[0].ws.sat, 1};
1227
312
            case Fragment::WRAP_V: return {subs[0].ws.sat, {}};
1228
16
            case Fragment::WRAP_J: return {subs[0].ws.sat, 1};
1229
140
            case Fragment::THRESH: {
1230
140
                auto sats = Vector(internal::MaxInt<uint32_t>(0));
1231
679
                for (const auto& sub : subs) {
1232
679
                    auto next_sats = Vector(sats[0] + sub.ws.dsat);
1233
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));
1234
679
                    next_sats.push_back(sats[sats.size() - 1] + sub.ws.sat);
1235
679
                    sats = std::move(next_sats);
1236
679
                }
1237
140
                assert(k < sats.size());
1238
140
                return {sats[k], sats[0]};
1239
140
            }
1240
28.2k
        }
1241
28.2k
        assert(false);
1242
0
    }
miniscript::Node<unsigned int>::CalcWitnessSize() const
Line
Count
Source
1191
1.72M
    internal::WitnessSize CalcWitnessSize() const {
1192
1.72M
        const uint32_t sig_size = IsTapscript(m_script_ctx) ? 1 + 65 : 1 + 72;
1193
1.72M
        const uint32_t pubkey_size = IsTapscript(m_script_ctx) ? 1 + 32 : 1 + 33;
1194
1.72M
        switch (fragment) {
1195
260
            case Fragment::JUST_0: return {{}, 0};
1196
13
            case Fragment::JUST_1:
1197
339
            case Fragment::OLDER:
1198
680
            case Fragment::AFTER: return {0, {}};
1199
1.46k
            case Fragment::PK_K: return {sig_size, 1};
1200
489
            case Fragment::PK_H: return {sig_size + pubkey_size, 1 + pubkey_size};
1201
42
            case Fragment::SHA256:
1202
93
            case Fragment::RIPEMD160:
1203
157
            case Fragment::HASH256:
1204
232
            case Fragment::HASH160: return {1 + 32, {}};
1205
138
            case Fragment::ANDOR: {
1206
138
                const auto sat{(subs[0].ws.sat + subs[1].ws.sat) | (subs[0].ws.dsat + subs[2].ws.sat)};
1207
138
                const auto dsat{subs[0].ws.dsat + subs[2].ws.dsat};
1208
138
                return {sat, dsat};
1209
157
            }
1210
732
            case Fragment::AND_V: return {subs[0].ws.sat + subs[1].ws.sat, {}};
1211
257
            case Fragment::AND_B: return {subs[0].ws.sat + subs[1].ws.sat, subs[0].ws.dsat + subs[1].ws.dsat};
1212
64
            case Fragment::OR_B: {
1213
64
                const auto sat{(subs[0].ws.dsat + subs[1].ws.sat) | (subs[0].ws.sat + subs[1].ws.dsat)};
1214
64
                const auto dsat{subs[0].ws.dsat + subs[1].ws.dsat};
1215
64
                return {sat, dsat};
1216
157
            }
1217
42
            case Fragment::OR_C: return {subs[0].ws.sat | (subs[0].ws.dsat + subs[1].ws.sat), {}};
1218
86
            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};
1219
256
            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)};
1220
128
            case Fragment::MULTI: return {k * sig_size + 1, k + 1};
1221
32
            case Fragment::MULTI_A: return {k * sig_size + static_cast<uint32_t>(keys.size()) - k, static_cast<uint32_t>(keys.size())};
1222
511
            case Fragment::WRAP_A:
1223
1.71M
            case Fragment::WRAP_N:
1224
1.71M
            case Fragment::WRAP_S:
1225
1.72M
            case Fragment::WRAP_C: return subs[0].ws;
1226
72
            case Fragment::WRAP_D: return {1 + 1 + subs[0].ws.sat, 1};
1227
809
            case Fragment::WRAP_V: return {subs[0].ws.sat, {}};
1228
0
            case Fragment::WRAP_J: return {subs[0].ws.sat, 1};
1229
246
            case Fragment::THRESH: {
1230
246
                auto sats = Vector(internal::MaxInt<uint32_t>(0));
1231
828
                for (const auto& sub : subs) {
1232
828
                    auto next_sats = Vector(sats[0] + sub.ws.dsat);
1233
2.16k
                    for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub.ws.dsat) | (sats[j - 1] + sub.ws.sat));
1234
828
                    next_sats.push_back(sats[sats.size() - 1] + sub.ws.sat);
1235
828
                    sats = std::move(next_sats);
1236
828
                }
1237
246
                assert(k < sats.size());
1238
246
                return {sats[k], sats[0]};
1239
246
            }
1240
1.72M
        }
1241
1.72M
        assert(false);
1242
0
    }
miniscript::Node<XOnlyPubKey>::CalcWitnessSize() const
Line
Count
Source
1191
5.27M
    internal::WitnessSize CalcWitnessSize() const {
1192
5.27M
        const uint32_t sig_size = IsTapscript(m_script_ctx) ? 1 + 65 : 1 + 72;
1193
5.27M
        const uint32_t pubkey_size = IsTapscript(m_script_ctx) ? 1 + 32 : 1 + 33;
1194
5.27M
        switch (fragment) {
1195
0
            case Fragment::JUST_0: return {{}, 0};
1196
0
            case Fragment::JUST_1:
1197
49
            case Fragment::OLDER:
1198
429
            case Fragment::AFTER: return {0, {}};
1199
2.21k
            case Fragment::PK_K: return {sig_size, 1};
1200
186
            case Fragment::PK_H: return {sig_size + pubkey_size, 1 + pubkey_size};
1201
0
            case Fragment::SHA256:
1202
0
            case Fragment::RIPEMD160:
1203
12
            case Fragment::HASH256:
1204
12
            case Fragment::HASH160: return {1 + 32, {}};
1205
0
            case Fragment::ANDOR: {
1206
0
                const auto sat{(subs[0].ws.sat + subs[1].ws.sat) | (subs[0].ws.dsat + subs[2].ws.sat)};
1207
0
                const auto dsat{subs[0].ws.dsat + subs[2].ws.dsat};
1208
0
                return {sat, dsat};
1209
12
            }
1210
473
            case Fragment::AND_V: return {subs[0].ws.sat + subs[1].ws.sat, {}};
1211
48
            case Fragment::AND_B: return {subs[0].ws.sat + subs[1].ws.sat, subs[0].ws.dsat + subs[1].ws.dsat};
1212
0
            case Fragment::OR_B: {
1213
0
                const auto sat{(subs[0].ws.dsat + subs[1].ws.sat) | (subs[0].ws.sat + subs[1].ws.dsat)};
1214
0
                const auto dsat{subs[0].ws.dsat + subs[1].ws.dsat};
1215
0
                return {sat, dsat};
1216
12
            }
1217
0
            case Fragment::OR_C: return {subs[0].ws.sat | (subs[0].ws.dsat + subs[1].ws.sat), {}};
1218
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};
1219
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)};
1220
0
            case Fragment::MULTI: return {k * sig_size + 1, k + 1};
1221
771
            case Fragment::MULTI_A: return {k * sig_size + static_cast<uint32_t>(keys.size()) - k, static_cast<uint32_t>(keys.size())};
1222
66
            case Fragment::WRAP_A:
1223
5.27M
            case Fragment::WRAP_N:
1224
5.27M
            case Fragment::WRAP_S:
1225
5.27M
            case Fragment::WRAP_C: return subs[0].ws;
1226
6
            case Fragment::WRAP_D: return {1 + 1 + subs[0].ws.sat, 1};
1227
479
            case Fragment::WRAP_V: return {subs[0].ws.sat, {}};
1228
0
            case Fragment::WRAP_J: return {subs[0].ws.sat, 1};
1229
18
            case Fragment::THRESH: {
1230
18
                auto sats = Vector(internal::MaxInt<uint32_t>(0));
1231
54
                for (const auto& sub : subs) {
1232
54
                    auto next_sats = Vector(sats[0] + sub.ws.dsat);
1233
108
                    for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub.ws.dsat) | (sats[j - 1] + sub.ws.sat));
1234
54
                    next_sats.push_back(sats[sats.size() - 1] + sub.ws.sat);
1235
54
                    sats = std::move(next_sats);
1236
54
                }
1237
18
                assert(k < sats.size());
1238
18
                return {sats[k], sats[0]};
1239
18
            }
1240
5.27M
        }
1241
5.27M
        assert(false);
1242
0
    }
1243
1244
    template<typename Ctx>
1245
8.09k
    internal::InputResult ProduceInput(const Ctx& ctx) const {
1246
8.09k
        using namespace internal;
1247
1248
        // Internal function which is invoked for every tree node, constructing satisfaction/dissatisfactions
1249
        // given those of its subnodes.
1250
6.89M
        auto helper = [&ctx](const Node& node, std::span<InputResult> subres) -> InputResult {
1251
6.89M
            switch (node.fragment) {
1252
377k
                case Fragment::PK_K: {
1253
377k
                    std::vector<unsigned char> sig;
1254
377k
                    Availability avail = ctx.Sign(node.keys[0], sig);
1255
377k
                    return {ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
1256
0
                }
1257
940
                case Fragment::PK_H: {
1258
940
                    std::vector<unsigned char> key = ctx.ToPKBytes(node.keys[0]), sig;
1259
940
                    Availability avail = ctx.Sign(node.keys[0], sig);
1260
940
                    return {ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
1261
0
                }
1262
927
                case Fragment::MULTI_A: {
1263
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1264
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1265
927
                    std::vector<InputStack> sats = Vector(EMPTY);
1266
94.2k
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1267
                        // Get the signature for the i'th key in reverse order (the signature for the first key needs to
1268
                        // be at the top of the stack, contrary to CHECKMULTISIG's satisfaction).
1269
93.3k
                        std::vector<unsigned char> sig;
1270
93.3k
                        Availability avail = ctx.Sign(node.keys[node.keys.size() - 1 - i], sig);
1271
                        // Compute signature stack for just this key.
1272
93.3k
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1273
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1274
                        // next_sats[j] are equal to either the existing sats[j] + ZERO, or sats[j-1] plus a signature
1275
                        // for the current (i'th) key. The very last element needs all signatures filled.
1276
93.3k
                        std::vector<InputStack> next_sats;
1277
93.3k
                        next_sats.push_back(sats[0] + ZERO);
1278
44.4M
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + ZERO) | (std::move(sats[j - 1]) + sat));
1279
93.3k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1280
                        // Switch over.
1281
93.3k
                        sats = std::move(next_sats);
1282
93.3k
                    }
1283
                    // The dissatisfaction consists of as many empty vectors as there are keys, which is the same as
1284
                    // satisfying 0 keys.
1285
927
                    auto& nsat{sats[0]};
1286
927
                    CHECK_NONFATAL(node.k != 0);
1287
927
                    assert(node.k < sats.size());
1288
927
                    return {std::move(nsat), std::move(sats[node.k])};
1289
927
                }
1290
384
                case Fragment::MULTI: {
1291
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1292
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1293
                    // sats[0] starts off being {0}, due to the CHECKMULTISIG bug that pops off one element too many.
1294
384
                    std::vector<InputStack> sats = Vector(ZERO);
1295
1.14k
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1296
756
                        std::vector<unsigned char> sig;
1297
756
                        Availability avail = ctx.Sign(node.keys[i], sig);
1298
                        // Compute signature stack for just the i'th key.
1299
756
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1300
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1301
                        // next_sats[j] are equal to either the existing sats[j], or sats[j-1] plus a signature for the
1302
                        // current (i'th) key. The very last element needs all signatures filled.
1303
756
                        std::vector<InputStack> next_sats;
1304
756
                        next_sats.push_back(sats[0]);
1305
1.20k
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
1306
756
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1307
                        // Switch over.
1308
756
                        sats = std::move(next_sats);
1309
756
                    }
1310
                    // The dissatisfaction consists of k+1 stack elements all equal to 0.
1311
384
                    InputStack nsat = ZERO;
1312
1.11k
                    for (size_t i = 0; i < node.k; ++i) nsat = std::move(nsat) + ZERO;
1313
384
                    assert(node.k < sats.size());
1314
384
                    return {std::move(nsat), std::move(sats[node.k])};
1315
384
                }
1316
495
                case Fragment::THRESH: {
1317
                    // sats[k] represents the best stack that satisfies k out of the *last* i subexpressions.
1318
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1319
                    // sats[0] starts off empty.
1320
495
                    std::vector<InputStack> sats = Vector(EMPTY);
1321
2.23k
                    for (size_t i = 0; i < subres.size(); ++i) {
1322
                        // Introduce an alias for the i'th last satisfaction/dissatisfaction.
1323
1.73k
                        auto& res = subres[subres.size() - i - 1];
1324
                        // Compute the next sats vector: next_sats[0] is sats[0] plus res.nsat (thus containing all dissatisfactions
1325
                        // so far. next_sats[j] is either sats[j] + res.nsat (reusing j earlier satisfactions) or sats[j-1] + res.sat
1326
                        // (reusing j-1 earlier satisfactions plus a new one). The very last next_sats[j] is all satisfactions.
1327
1.73k
                        std::vector<InputStack> next_sats;
1328
1.73k
                        next_sats.push_back(sats[0] + res.nsat);
1329
4.51k
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + res.nsat) | (std::move(sats[j - 1]) + res.sat));
1330
1.73k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
1331
                        // Switch over.
1332
1.73k
                        sats = std::move(next_sats);
1333
1.73k
                    }
1334
                    // At this point, sats[k].sat is the best satisfaction for the overall thresh() node. The best dissatisfaction
1335
                    // is computed by gathering all sats[i].nsat for i != k.
1336
495
                    InputStack nsat = INVALID;
1337
2.72k
                    for (size_t i = 0; i < sats.size(); ++i) {
1338
                        // i==k is the satisfaction; i==0 is the canonical dissatisfaction;
1339
                        // the rest are non-canonical (a no-signature dissatisfaction - the i=0
1340
                        // form - is always available) and malleable (due to overcompleteness).
1341
                        // Marking the solutions malleable here is not strictly necessary, as they
1342
                        // should already never be picked in non-malleable solutions due to the
1343
                        // availability of the i=0 form.
1344
2.23k
                        if (i != 0 && i != node.k) sats[i].SetMalleable().SetNonCanon();
1345
                        // Include all dissatisfactions (even these non-canonical ones) in nsat.
1346
2.23k
                        if (i != node.k) nsat = std::move(nsat) | std::move(sats[i]);
1347
2.23k
                    }
1348
495
                    assert(node.k < sats.size());
1349
495
                    return {std::move(nsat), std::move(sats[node.k])};
1350
495
                }
1351
37.0k
                case Fragment::OLDER: {
1352
37.0k
                    return {INVALID, ctx.CheckOlder(node.k) ? EMPTY : INVALID};
1353
495
                }
1354
1.93k
                case Fragment::AFTER: {
1355
1.93k
                    return {INVALID, ctx.CheckAfter(node.k) ? EMPTY : INVALID};
1356
495
                }
1357
522
                case Fragment::SHA256: {
1358
522
                    std::vector<unsigned char> preimage;
1359
522
                    Availability avail = ctx.SatSHA256(node.data, preimage);
1360
522
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1361
495
                }
1362
222
                case Fragment::RIPEMD160: {
1363
222
                    std::vector<unsigned char> preimage;
1364
222
                    Availability avail = ctx.SatRIPEMD160(node.data, preimage);
1365
222
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1366
495
                }
1367
396
                case Fragment::HASH256: {
1368
396
                    std::vector<unsigned char> preimage;
1369
396
                    Availability avail = ctx.SatHASH256(node.data, preimage);
1370
396
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1371
495
                }
1372
168
                case Fragment::HASH160: {
1373
168
                    std::vector<unsigned char> preimage;
1374
168
                    Availability avail = ctx.SatHASH160(node.data, preimage);
1375
168
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1376
495
                }
1377
1.90k
                case Fragment::AND_V: {
1378
1.90k
                    auto& x = subres[0], &y = subres[1];
1379
                    // As the dissatisfaction here only consist of a single option, it doesn't
1380
                    // actually need to be listed (it's not required for reasoning about malleability of
1381
                    // other options), and is never required (no valid miniscript relies on the ability
1382
                    // to satisfy the type V left subexpression). It's still listed here for
1383
                    // completeness, as a hypothetical (not currently implemented) satisfier that doesn't
1384
                    // care about malleability might in some cases prefer it still.
1385
1.90k
                    return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
1386
495
                }
1387
407k
                case Fragment::AND_B: {
1388
407k
                    auto& x = subres[0], &y = subres[1];
1389
                    // Note that it is not strictly necessary to mark the 2nd and 3rd dissatisfaction here
1390
                    // as malleable. While they are definitely malleable, they are also non-canonical due
1391
                    // to the guaranteed existence of a no-signature other dissatisfaction (the 1st)
1392
                    // option. Because of that, the 2nd and 3rd option will never be chosen, even if they
1393
                    // weren't marked as malleable.
1394
407k
                    return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
1395
495
                }
1396
144
                case Fragment::OR_B: {
1397
144
                    auto& x = subres[0], &z = subres[1];
1398
                    // The (sat(Z) sat(X)) solution is overcomplete (attacker can change either into dsat).
1399
144
                    return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
1400
495
                }
1401
90
                case Fragment::OR_C: {
1402
90
                    auto& x = subres[0], &z = subres[1];
1403
90
                    return {INVALID, std::move(x.sat) | (z.sat + x.nsat)};
1404
495
                }
1405
320
                case Fragment::OR_D: {
1406
320
                    auto& x = subres[0], &z = subres[1];
1407
320
                    return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
1408
495
                }
1409
1.81k
                case Fragment::OR_I: {
1410
1.81k
                    auto& x = subres[0], &z = subres[1];
1411
1.81k
                    return {(x.nsat + ONE) | (z.nsat + ZERO), (x.sat + ONE) | (z.sat + ZERO)};
1412
495
                }
1413
716
                case Fragment::ANDOR: {
1414
716
                    auto& x = subres[0], &y = subres[1], &z = subres[2];
1415
716
                    return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
1416
495
                }
1417
408k
                case Fragment::WRAP_A:
1418
409k
                case Fragment::WRAP_S:
1419
787k
                case Fragment::WRAP_C:
1420
6.05M
                case Fragment::WRAP_N:
1421
6.05M
                    return std::move(subres[0]);
1422
126
                case Fragment::WRAP_D: {
1423
126
                    auto &x = subres[0];
1424
126
                    return {ZERO, x.sat + ONE};
1425
787k
                }
1426
198
                case Fragment::WRAP_J: {
1427
198
                    auto &x = subres[0];
1428
                    // If a dissatisfaction with a nonzero top stack element exists, an alternative dissatisfaction exists.
1429
                    // As the dissatisfaction logic currently doesn't keep track of this nonzeroness property, and thus even
1430
                    // if a dissatisfaction with a top zero element is found, we don't know whether another one with a
1431
                    // nonzero top stack element exists. Make the conservative assumption that whenever the subexpression is weakly
1432
                    // dissatisfiable, this alternative dissatisfaction exists and leads to malleability.
1433
198
                    return {InputStack(ZERO).SetMalleable(x.nsat.available != Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
1434
787k
                }
1435
2.23k
                case Fragment::WRAP_V: {
1436
2.23k
                    auto &x = subres[0];
1437
2.23k
                    return {INVALID, std::move(x.sat)};
1438
787k
                }
1439
1.74k
                case Fragment::JUST_0: return {EMPTY, INVALID};
1440
972
                case Fragment::JUST_1: return {INVALID, EMPTY};
1441
6.89M
            }
1442
6.89M
            assert(false);
1443
0
            return {INVALID, INVALID};
1444
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
1250
1.61M
        auto helper = [&ctx](const Node& node, std::span<InputResult> subres) -> InputResult {
1251
1.61M
            switch (node.fragment) {
1252
374k
                case Fragment::PK_K: {
1253
374k
                    std::vector<unsigned char> sig;
1254
374k
                    Availability avail = ctx.Sign(node.keys[0], sig);
1255
374k
                    return {ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
1256
0
                }
1257
708
                case Fragment::PK_H: {
1258
708
                    std::vector<unsigned char> key = ctx.ToPKBytes(node.keys[0]), sig;
1259
708
                    Availability avail = ctx.Sign(node.keys[0], sig);
1260
708
                    return {ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
1261
0
                }
1262
156
                case Fragment::MULTI_A: {
1263
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1264
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1265
156
                    std::vector<InputStack> sats = Vector(EMPTY);
1266
2.97k
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1267
                        // Get the signature for the i'th key in reverse order (the signature for the first key needs to
1268
                        // be at the top of the stack, contrary to CHECKMULTISIG's satisfaction).
1269
2.82k
                        std::vector<unsigned char> sig;
1270
2.82k
                        Availability avail = ctx.Sign(node.keys[node.keys.size() - 1 - i], sig);
1271
                        // Compute signature stack for just this key.
1272
2.82k
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1273
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1274
                        // next_sats[j] are equal to either the existing sats[j] + ZERO, or sats[j-1] plus a signature
1275
                        // for the current (i'th) key. The very last element needs all signatures filled.
1276
2.82k
                        std::vector<InputStack> next_sats;
1277
2.82k
                        next_sats.push_back(sats[0] + ZERO);
1278
30.5k
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + ZERO) | (std::move(sats[j - 1]) + sat));
1279
2.82k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1280
                        // Switch over.
1281
2.82k
                        sats = std::move(next_sats);
1282
2.82k
                    }
1283
                    // The dissatisfaction consists of as many empty vectors as there are keys, which is the same as
1284
                    // satisfying 0 keys.
1285
156
                    auto& nsat{sats[0]};
1286
156
                    CHECK_NONFATAL(node.k != 0);
1287
156
                    assert(node.k < sats.size());
1288
156
                    return {std::move(nsat), std::move(sats[node.k])};
1289
156
                }
1290
360
                case Fragment::MULTI: {
1291
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1292
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1293
                    // sats[0] starts off being {0}, due to the CHECKMULTISIG bug that pops off one element too many.
1294
360
                    std::vector<InputStack> sats = Vector(ZERO);
1295
1.06k
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1296
708
                        std::vector<unsigned char> sig;
1297
708
                        Availability avail = ctx.Sign(node.keys[i], sig);
1298
                        // Compute signature stack for just the i'th key.
1299
708
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1300
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1301
                        // next_sats[j] are equal to either the existing sats[j], or sats[j-1] plus a signature for the
1302
                        // current (i'th) key. The very last element needs all signatures filled.
1303
708
                        std::vector<InputStack> next_sats;
1304
708
                        next_sats.push_back(sats[0]);
1305
1.12k
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
1306
708
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1307
                        // Switch over.
1308
708
                        sats = std::move(next_sats);
1309
708
                    }
1310
                    // The dissatisfaction consists of k+1 stack elements all equal to 0.
1311
360
                    InputStack nsat = ZERO;
1312
1.06k
                    for (size_t i = 0; i < node.k; ++i) nsat = std::move(nsat) + ZERO;
1313
360
                    assert(node.k < sats.size());
1314
360
                    return {std::move(nsat), std::move(sats[node.k])};
1315
360
                }
1316
372
                case Fragment::THRESH: {
1317
                    // sats[k] represents the best stack that satisfies k out of the *last* i subexpressions.
1318
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1319
                    // sats[0] starts off empty.
1320
372
                    std::vector<InputStack> sats = Vector(EMPTY);
1321
1.47k
                    for (size_t i = 0; i < subres.size(); ++i) {
1322
                        // Introduce an alias for the i'th last satisfaction/dissatisfaction.
1323
1.10k
                        auto& res = subres[subres.size() - i - 1];
1324
                        // Compute the next sats vector: next_sats[0] is sats[0] plus res.nsat (thus containing all dissatisfactions
1325
                        // so far. next_sats[j] is either sats[j] + res.nsat (reusing j earlier satisfactions) or sats[j-1] + res.sat
1326
                        // (reusing j-1 earlier satisfactions plus a new one). The very last next_sats[j] is all satisfactions.
1327
1.10k
                        std::vector<InputStack> next_sats;
1328
1.10k
                        next_sats.push_back(sats[0] + res.nsat);
1329
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));
1330
1.10k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
1331
                        // Switch over.
1332
1.10k
                        sats = std::move(next_sats);
1333
1.10k
                    }
1334
                    // At this point, sats[k].sat is the best satisfaction for the overall thresh() node. The best dissatisfaction
1335
                    // is computed by gathering all sats[i].nsat for i != k.
1336
372
                    InputStack nsat = INVALID;
1337
1.84k
                    for (size_t i = 0; i < sats.size(); ++i) {
1338
                        // i==k is the satisfaction; i==0 is the canonical dissatisfaction;
1339
                        // the rest are non-canonical (a no-signature dissatisfaction - the i=0
1340
                        // form - is always available) and malleable (due to overcompleteness).
1341
                        // Marking the solutions malleable here is not strictly necessary, as they
1342
                        // should already never be picked in non-malleable solutions due to the
1343
                        // availability of the i=0 form.
1344
1.47k
                        if (i != 0 && i != node.k) sats[i].SetMalleable().SetNonCanon();
1345
                        // Include all dissatisfactions (even these non-canonical ones) in nsat.
1346
1.47k
                        if (i != node.k) nsat = std::move(nsat) | std::move(sats[i]);
1347
1.47k
                    }
1348
372
                    assert(node.k < sats.size());
1349
372
                    return {std::move(nsat), std::move(sats[node.k])};
1350
372
                }
1351
36.9k
                case Fragment::OLDER: {
1352
36.9k
                    return {INVALID, ctx.CheckOlder(node.k) ? EMPTY : INVALID};
1353
372
                }
1354
1.30k
                case Fragment::AFTER: {
1355
1.30k
                    return {INVALID, ctx.CheckAfter(node.k) ? EMPTY : INVALID};
1356
372
                }
1357
504
                case Fragment::SHA256: {
1358
504
                    std::vector<unsigned char> preimage;
1359
504
                    Availability avail = ctx.SatSHA256(node.data, preimage);
1360
504
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1361
372
                }
1362
210
                case Fragment::RIPEMD160: {
1363
210
                    std::vector<unsigned char> preimage;
1364
210
                    Availability avail = ctx.SatRIPEMD160(node.data, preimage);
1365
210
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1366
372
                }
1367
372
                case Fragment::HASH256: {
1368
372
                    std::vector<unsigned char> preimage;
1369
372
                    Availability avail = ctx.SatHASH256(node.data, preimage);
1370
372
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1371
372
                }
1372
156
                case Fragment::HASH160: {
1373
156
                    std::vector<unsigned char> preimage;
1374
156
                    Availability avail = ctx.SatHASH160(node.data, preimage);
1375
156
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1376
372
                }
1377
1.32k
                case Fragment::AND_V: {
1378
1.32k
                    auto& x = subres[0], &y = subres[1];
1379
                    // As the dissatisfaction here only consist of a single option, it doesn't
1380
                    // actually need to be listed (it's not required for reasoning about malleability of
1381
                    // other options), and is never required (no valid miniscript relies on the ability
1382
                    // to satisfy the type V left subexpression). It's still listed here for
1383
                    // completeness, as a hypothetical (not currently implemented) satisfier that doesn't
1384
                    // care about malleability might in some cases prefer it still.
1385
1.32k
                    return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
1386
372
                }
1387
407k
                case Fragment::AND_B: {
1388
407k
                    auto& x = subres[0], &y = subres[1];
1389
                    // Note that it is not strictly necessary to mark the 2nd and 3rd dissatisfaction here
1390
                    // as malleable. While they are definitely malleable, they are also non-canonical due
1391
                    // to the guaranteed existence of a no-signature other dissatisfaction (the 1st)
1392
                    // option. Because of that, the 2nd and 3rd option will never be chosen, even if they
1393
                    // weren't marked as malleable.
1394
407k
                    return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
1395
372
                }
1396
144
                case Fragment::OR_B: {
1397
144
                    auto& x = subres[0], &z = subres[1];
1398
                    // The (sat(Z) sat(X)) solution is overcomplete (attacker can change either into dsat).
1399
144
                    return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
1400
372
                }
1401
90
                case Fragment::OR_C: {
1402
90
                    auto& x = subres[0], &z = subres[1];
1403
90
                    return {INVALID, std::move(x.sat) | (z.sat + x.nsat)};
1404
372
                }
1405
312
                case Fragment::OR_D: {
1406
312
                    auto& x = subres[0], &z = subres[1];
1407
312
                    return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
1408
372
                }
1409
1.59k
                case Fragment::OR_I: {
1410
1.59k
                    auto& x = subres[0], &z = subres[1];
1411
1.59k
                    return {(x.nsat + ONE) | (z.nsat + ZERO), (x.sat + ONE) | (z.sat + ZERO)};
1412
372
                }
1413
672
                case Fragment::ANDOR: {
1414
672
                    auto& x = subres[0], &y = subres[1], &z = subres[2];
1415
672
                    return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
1416
372
                }
1417
408k
                case Fragment::WRAP_A:
1418
408k
                case Fragment::WRAP_S:
1419
783k
                case Fragment::WRAP_C:
1420
783k
                case Fragment::WRAP_N:
1421
783k
                    return std::move(subres[0]);
1422
96
                case Fragment::WRAP_D: {
1423
96
                    auto &x = subres[0];
1424
96
                    return {ZERO, x.sat + ONE};
1425
783k
                }
1426
198
                case Fragment::WRAP_J: {
1427
198
                    auto &x = subres[0];
1428
                    // If a dissatisfaction with a nonzero top stack element exists, an alternative dissatisfaction exists.
1429
                    // As the dissatisfaction logic currently doesn't keep track of this nonzeroness property, and thus even
1430
                    // if a dissatisfaction with a top zero element is found, we don't know whether another one with a
1431
                    // nonzero top stack element exists. Make the conservative assumption that whenever the subexpression is weakly
1432
                    // dissatisfiable, this alternative dissatisfaction exists and leads to malleability.
1433
198
                    return {InputStack(ZERO).SetMalleable(x.nsat.available != Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
1434
783k
                }
1435
1.62k
                case Fragment::WRAP_V: {
1436
1.62k
                    auto &x = subres[0];
1437
1.62k
                    return {INVALID, std::move(x.sat)};
1438
783k
                }
1439
1.50k
                case Fragment::JUST_0: return {EMPTY, INVALID};
1440
972
                case Fragment::JUST_1: return {INVALID, EMPTY};
1441
1.61M
            }
1442
1.61M
            assert(false);
1443
0
            return {INVALID, INVALID};
1444
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
1250
5.27M
        auto helper = [&ctx](const Node& node, std::span<InputResult> subres) -> InputResult {
1251
5.27M
            switch (node.fragment) {
1252
2.21k
                case Fragment::PK_K: {
1253
2.21k
                    std::vector<unsigned char> sig;
1254
2.21k
                    Availability avail = ctx.Sign(node.keys[0], sig);
1255
2.21k
                    return {ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
1256
0
                }
1257
186
                case Fragment::PK_H: {
1258
186
                    std::vector<unsigned char> key = ctx.ToPKBytes(node.keys[0]), sig;
1259
186
                    Availability avail = ctx.Sign(node.keys[0], sig);
1260
186
                    return {ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
1261
0
                }
1262
771
                case Fragment::MULTI_A: {
1263
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1264
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1265
771
                    std::vector<InputStack> sats = Vector(EMPTY);
1266
91.2k
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1267
                        // Get the signature for the i'th key in reverse order (the signature for the first key needs to
1268
                        // be at the top of the stack, contrary to CHECKMULTISIG's satisfaction).
1269
90.5k
                        std::vector<unsigned char> sig;
1270
90.5k
                        Availability avail = ctx.Sign(node.keys[node.keys.size() - 1 - i], sig);
1271
                        // Compute signature stack for just this key.
1272
90.5k
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1273
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1274
                        // next_sats[j] are equal to either the existing sats[j] + ZERO, or sats[j-1] plus a signature
1275
                        // for the current (i'th) key. The very last element needs all signatures filled.
1276
90.5k
                        std::vector<InputStack> next_sats;
1277
90.5k
                        next_sats.push_back(sats[0] + ZERO);
1278
44.4M
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + ZERO) | (std::move(sats[j - 1]) + sat));
1279
90.5k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1280
                        // Switch over.
1281
90.5k
                        sats = std::move(next_sats);
1282
90.5k
                    }
1283
                    // The dissatisfaction consists of as many empty vectors as there are keys, which is the same as
1284
                    // satisfying 0 keys.
1285
771
                    auto& nsat{sats[0]};
1286
771
                    CHECK_NONFATAL(node.k != 0);
1287
771
                    assert(node.k < sats.size());
1288
771
                    return {std::move(nsat), std::move(sats[node.k])};
1289
771
                }
1290
0
                case Fragment::MULTI: {
1291
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1292
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1293
                    // sats[0] starts off being {0}, due to the CHECKMULTISIG bug that pops off one element too many.
1294
0
                    std::vector<InputStack> sats = Vector(ZERO);
1295
0
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1296
0
                        std::vector<unsigned char> sig;
1297
0
                        Availability avail = ctx.Sign(node.keys[i], sig);
1298
                        // Compute signature stack for just the i'th key.
1299
0
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1300
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1301
                        // next_sats[j] are equal to either the existing sats[j], or sats[j-1] plus a signature for the
1302
                        // current (i'th) key. The very last element needs all signatures filled.
1303
0
                        std::vector<InputStack> next_sats;
1304
0
                        next_sats.push_back(sats[0]);
1305
0
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
1306
0
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1307
                        // Switch over.
1308
0
                        sats = std::move(next_sats);
1309
0
                    }
1310
                    // The dissatisfaction consists of k+1 stack elements all equal to 0.
1311
0
                    InputStack nsat = ZERO;
1312
0
                    for (size_t i = 0; i < node.k; ++i) nsat = std::move(nsat) + ZERO;
1313
0
                    assert(node.k < sats.size());
1314
0
                    return {std::move(nsat), std::move(sats[node.k])};
1315
0
                }
1316
18
                case Fragment::THRESH: {
1317
                    // sats[k] represents the best stack that satisfies k out of the *last* i subexpressions.
1318
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1319
                    // sats[0] starts off empty.
1320
18
                    std::vector<InputStack> sats = Vector(EMPTY);
1321
72
                    for (size_t i = 0; i < subres.size(); ++i) {
1322
                        // Introduce an alias for the i'th last satisfaction/dissatisfaction.
1323
54
                        auto& res = subres[subres.size() - i - 1];
1324
                        // Compute the next sats vector: next_sats[0] is sats[0] plus res.nsat (thus containing all dissatisfactions
1325
                        // so far. next_sats[j] is either sats[j] + res.nsat (reusing j earlier satisfactions) or sats[j-1] + res.sat
1326
                        // (reusing j-1 earlier satisfactions plus a new one). The very last next_sats[j] is all satisfactions.
1327
54
                        std::vector<InputStack> next_sats;
1328
54
                        next_sats.push_back(sats[0] + res.nsat);
1329
108
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + res.nsat) | (std::move(sats[j - 1]) + res.sat));
1330
54
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
1331
                        // Switch over.
1332
54
                        sats = std::move(next_sats);
1333
54
                    }
1334
                    // At this point, sats[k].sat is the best satisfaction for the overall thresh() node. The best dissatisfaction
1335
                    // is computed by gathering all sats[i].nsat for i != k.
1336
18
                    InputStack nsat = INVALID;
1337
90
                    for (size_t i = 0; i < sats.size(); ++i) {
1338
                        // i==k is the satisfaction; i==0 is the canonical dissatisfaction;
1339
                        // the rest are non-canonical (a no-signature dissatisfaction - the i=0
1340
                        // form - is always available) and malleable (due to overcompleteness).
1341
                        // Marking the solutions malleable here is not strictly necessary, as they
1342
                        // should already never be picked in non-malleable solutions due to the
1343
                        // availability of the i=0 form.
1344
72
                        if (i != 0 && i != node.k) sats[i].SetMalleable().SetNonCanon();
1345
                        // Include all dissatisfactions (even these non-canonical ones) in nsat.
1346
72
                        if (i != node.k) nsat = std::move(nsat) | std::move(sats[i]);
1347
72
                    }
1348
18
                    assert(node.k < sats.size());
1349
18
                    return {std::move(nsat), std::move(sats[node.k])};
1350
18
                }
1351
49
                case Fragment::OLDER: {
1352
49
                    return {INVALID, ctx.CheckOlder(node.k) ? EMPTY : INVALID};
1353
18
                }
1354
380
                case Fragment::AFTER: {
1355
380
                    return {INVALID, ctx.CheckAfter(node.k) ? EMPTY : INVALID};
1356
18
                }
1357
0
                case Fragment::SHA256: {
1358
0
                    std::vector<unsigned char> preimage;
1359
0
                    Availability avail = ctx.SatSHA256(node.data, preimage);
1360
0
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1361
18
                }
1362
0
                case Fragment::RIPEMD160: {
1363
0
                    std::vector<unsigned char> preimage;
1364
0
                    Availability avail = ctx.SatRIPEMD160(node.data, preimage);
1365
0
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1366
18
                }
1367
12
                case Fragment::HASH256: {
1368
12
                    std::vector<unsigned char> preimage;
1369
12
                    Availability avail = ctx.SatHASH256(node.data, preimage);
1370
12
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1371
18
                }
1372
0
                case Fragment::HASH160: {
1373
0
                    std::vector<unsigned char> preimage;
1374
0
                    Availability avail = ctx.SatHASH160(node.data, preimage);
1375
0
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1376
18
                }
1377
473
                case Fragment::AND_V: {
1378
473
                    auto& x = subres[0], &y = subres[1];
1379
                    // As the dissatisfaction here only consist of a single option, it doesn't
1380
                    // actually need to be listed (it's not required for reasoning about malleability of
1381
                    // other options), and is never required (no valid miniscript relies on the ability
1382
                    // to satisfy the type V left subexpression). It's still listed here for
1383
                    // completeness, as a hypothetical (not currently implemented) satisfier that doesn't
1384
                    // care about malleability might in some cases prefer it still.
1385
473
                    return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
1386
18
                }
1387
48
                case Fragment::AND_B: {
1388
48
                    auto& x = subres[0], &y = subres[1];
1389
                    // Note that it is not strictly necessary to mark the 2nd and 3rd dissatisfaction here
1390
                    // as malleable. While they are definitely malleable, they are also non-canonical due
1391
                    // to the guaranteed existence of a no-signature other dissatisfaction (the 1st)
1392
                    // option. Because of that, the 2nd and 3rd option will never be chosen, even if they
1393
                    // weren't marked as malleable.
1394
48
                    return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
1395
18
                }
1396
0
                case Fragment::OR_B: {
1397
0
                    auto& x = subres[0], &z = subres[1];
1398
                    // The (sat(Z) sat(X)) solution is overcomplete (attacker can change either into dsat).
1399
0
                    return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
1400
18
                }
1401
0
                case Fragment::OR_C: {
1402
0
                    auto& x = subres[0], &z = subres[1];
1403
0
                    return {INVALID, std::move(x.sat) | (z.sat + x.nsat)};
1404
18
                }
1405
0
                case Fragment::OR_D: {
1406
0
                    auto& x = subres[0], &z = subres[1];
1407
0
                    return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
1408
18
                }
1409
0
                case Fragment::OR_I: {
1410
0
                    auto& x = subres[0], &z = subres[1];
1411
0
                    return {(x.nsat + ONE) | (z.nsat + ZERO), (x.sat + ONE) | (z.sat + ZERO)};
1412
18
                }
1413
0
                case Fragment::ANDOR: {
1414
0
                    auto& x = subres[0], &y = subres[1], &z = subres[2];
1415
0
                    return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
1416
18
                }
1417
66
                case Fragment::WRAP_A:
1418
84
                case Fragment::WRAP_S:
1419
2.48k
                case Fragment::WRAP_C:
1420
5.27M
                case Fragment::WRAP_N:
1421
5.27M
                    return std::move(subres[0]);
1422
6
                case Fragment::WRAP_D: {
1423
6
                    auto &x = subres[0];
1424
6
                    return {ZERO, x.sat + ONE};
1425
2.48k
                }
1426
0
                case Fragment::WRAP_J: {
1427
0
                    auto &x = subres[0];
1428
                    // If a dissatisfaction with a nonzero top stack element exists, an alternative dissatisfaction exists.
1429
                    // As the dissatisfaction logic currently doesn't keep track of this nonzeroness property, and thus even
1430
                    // if a dissatisfaction with a top zero element is found, we don't know whether another one with a
1431
                    // nonzero top stack element exists. Make the conservative assumption that whenever the subexpression is weakly
1432
                    // dissatisfiable, this alternative dissatisfaction exists and leads to malleability.
1433
0
                    return {InputStack(ZERO).SetMalleable(x.nsat.available != Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
1434
2.48k
                }
1435
479
                case Fragment::WRAP_V: {
1436
479
                    auto &x = subres[0];
1437
479
                    return {INVALID, std::move(x.sat)};
1438
2.48k
                }
1439
0
                case Fragment::JUST_0: return {EMPTY, INVALID};
1440
0
                case Fragment::JUST_1: return {INVALID, EMPTY};
1441
5.27M
            }
1442
5.27M
            assert(false);
1443
0
            return {INVALID, INVALID};
1444
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
1250
3.01k
        auto helper = [&ctx](const Node& node, std::span<InputResult> subres) -> InputResult {
1251
3.01k
            switch (node.fragment) {
1252
450
                case Fragment::PK_K: {
1253
450
                    std::vector<unsigned char> sig;
1254
450
                    Availability avail = ctx.Sign(node.keys[0], sig);
1255
450
                    return {ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
1256
0
                }
1257
46
                case Fragment::PK_H: {
1258
46
                    std::vector<unsigned char> key = ctx.ToPKBytes(node.keys[0]), sig;
1259
46
                    Availability avail = ctx.Sign(node.keys[0], sig);
1260
46
                    return {ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
1261
0
                }
1262
0
                case Fragment::MULTI_A: {
1263
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1264
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1265
0
                    std::vector<InputStack> sats = Vector(EMPTY);
1266
0
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1267
                        // Get the signature for the i'th key in reverse order (the signature for the first key needs to
1268
                        // be at the top of the stack, contrary to CHECKMULTISIG's satisfaction).
1269
0
                        std::vector<unsigned char> sig;
1270
0
                        Availability avail = ctx.Sign(node.keys[node.keys.size() - 1 - i], sig);
1271
                        // Compute signature stack for just this key.
1272
0
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1273
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1274
                        // next_sats[j] are equal to either the existing sats[j] + ZERO, or sats[j-1] plus a signature
1275
                        // for the current (i'th) key. The very last element needs all signatures filled.
1276
0
                        std::vector<InputStack> next_sats;
1277
0
                        next_sats.push_back(sats[0] + ZERO);
1278
0
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + ZERO) | (std::move(sats[j - 1]) + sat));
1279
0
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1280
                        // Switch over.
1281
0
                        sats = std::move(next_sats);
1282
0
                    }
1283
                    // The dissatisfaction consists of as many empty vectors as there are keys, which is the same as
1284
                    // satisfying 0 keys.
1285
0
                    auto& nsat{sats[0]};
1286
0
                    CHECK_NONFATAL(node.k != 0);
1287
0
                    assert(node.k < sats.size());
1288
0
                    return {std::move(nsat), std::move(sats[node.k])};
1289
0
                }
1290
24
                case Fragment::MULTI: {
1291
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1292
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1293
                    // sats[0] starts off being {0}, due to the CHECKMULTISIG bug that pops off one element too many.
1294
24
                    std::vector<InputStack> sats = Vector(ZERO);
1295
72
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1296
48
                        std::vector<unsigned char> sig;
1297
48
                        Availability avail = ctx.Sign(node.keys[i], sig);
1298
                        // Compute signature stack for just the i'th key.
1299
48
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1300
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1301
                        // next_sats[j] are equal to either the existing sats[j], or sats[j-1] plus a signature for the
1302
                        // current (i'th) key. The very last element needs all signatures filled.
1303
48
                        std::vector<InputStack> next_sats;
1304
48
                        next_sats.push_back(sats[0]);
1305
72
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
1306
48
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1307
                        // Switch over.
1308
48
                        sats = std::move(next_sats);
1309
48
                    }
1310
                    // The dissatisfaction consists of k+1 stack elements all equal to 0.
1311
24
                    InputStack nsat = ZERO;
1312
48
                    for (size_t i = 0; i < node.k; ++i) nsat = std::move(nsat) + ZERO;
1313
24
                    assert(node.k < sats.size());
1314
24
                    return {std::move(nsat), std::move(sats[node.k])};
1315
24
                }
1316
105
                case Fragment::THRESH: {
1317
                    // sats[k] represents the best stack that satisfies k out of the *last* i subexpressions.
1318
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1319
                    // sats[0] starts off empty.
1320
105
                    std::vector<InputStack> sats = Vector(EMPTY);
1321
682
                    for (size_t i = 0; i < subres.size(); ++i) {
1322
                        // Introduce an alias for the i'th last satisfaction/dissatisfaction.
1323
577
                        auto& res = subres[subres.size() - i - 1];
1324
                        // Compute the next sats vector: next_sats[0] is sats[0] plus res.nsat (thus containing all dissatisfactions
1325
                        // so far. next_sats[j] is either sats[j] + res.nsat (reusing j earlier satisfactions) or sats[j-1] + res.sat
1326
                        // (reusing j-1 earlier satisfactions plus a new one). The very last next_sats[j] is all satisfactions.
1327
577
                        std::vector<InputStack> next_sats;
1328
577
                        next_sats.push_back(sats[0] + res.nsat);
1329
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));
1330
577
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
1331
                        // Switch over.
1332
577
                        sats = std::move(next_sats);
1333
577
                    }
1334
                    // At this point, sats[k].sat is the best satisfaction for the overall thresh() node. The best dissatisfaction
1335
                    // is computed by gathering all sats[i].nsat for i != k.
1336
105
                    InputStack nsat = INVALID;
1337
787
                    for (size_t i = 0; i < sats.size(); ++i) {
1338
                        // i==k is the satisfaction; i==0 is the canonical dissatisfaction;
1339
                        // the rest are non-canonical (a no-signature dissatisfaction - the i=0
1340
                        // form - is always available) and malleable (due to overcompleteness).
1341
                        // Marking the solutions malleable here is not strictly necessary, as they
1342
                        // should already never be picked in non-malleable solutions due to the
1343
                        // availability of the i=0 form.
1344
682
                        if (i != 0 && i != node.k) sats[i].SetMalleable().SetNonCanon();
1345
                        // Include all dissatisfactions (even these non-canonical ones) in nsat.
1346
682
                        if (i != node.k) nsat = std::move(nsat) | std::move(sats[i]);
1347
682
                    }
1348
105
                    assert(node.k < sats.size());
1349
105
                    return {std::move(nsat), std::move(sats[node.k])};
1350
105
                }
1351
58
                case Fragment::OLDER: {
1352
58
                    return {INVALID, ctx.CheckOlder(node.k) ? EMPTY : INVALID};
1353
105
                }
1354
245
                case Fragment::AFTER: {
1355
245
                    return {INVALID, ctx.CheckAfter(node.k) ? EMPTY : INVALID};
1356
105
                }
1357
18
                case Fragment::SHA256: {
1358
18
                    std::vector<unsigned char> preimage;
1359
18
                    Availability avail = ctx.SatSHA256(node.data, preimage);
1360
18
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1361
105
                }
1362
12
                case Fragment::RIPEMD160: {
1363
12
                    std::vector<unsigned char> preimage;
1364
12
                    Availability avail = ctx.SatRIPEMD160(node.data, preimage);
1365
12
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1366
105
                }
1367
12
                case Fragment::HASH256: {
1368
12
                    std::vector<unsigned char> preimage;
1369
12
                    Availability avail = ctx.SatHASH256(node.data, preimage);
1370
12
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1371
105
                }
1372
12
                case Fragment::HASH160: {
1373
12
                    std::vector<unsigned char> preimage;
1374
12
                    Availability avail = ctx.SatHASH160(node.data, preimage);
1375
12
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1376
105
                }
1377
108
                case Fragment::AND_V: {
1378
108
                    auto& x = subres[0], &y = subres[1];
1379
                    // As the dissatisfaction here only consist of a single option, it doesn't
1380
                    // actually need to be listed (it's not required for reasoning about malleability of
1381
                    // other options), and is never required (no valid miniscript relies on the ability
1382
                    // to satisfy the type V left subexpression). It's still listed here for
1383
                    // completeness, as a hypothetical (not currently implemented) satisfier that doesn't
1384
                    // care about malleability might in some cases prefer it still.
1385
108
                    return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
1386
105
                }
1387
8
                case Fragment::AND_B: {
1388
8
                    auto& x = subres[0], &y = subres[1];
1389
                    // Note that it is not strictly necessary to mark the 2nd and 3rd dissatisfaction here
1390
                    // as malleable. While they are definitely malleable, they are also non-canonical due
1391
                    // to the guaranteed existence of a no-signature other dissatisfaction (the 1st)
1392
                    // option. Because of that, the 2nd and 3rd option will never be chosen, even if they
1393
                    // weren't marked as malleable.
1394
8
                    return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
1395
105
                }
1396
0
                case Fragment::OR_B: {
1397
0
                    auto& x = subres[0], &z = subres[1];
1398
                    // The (sat(Z) sat(X)) solution is overcomplete (attacker can change either into dsat).
1399
0
                    return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
1400
105
                }
1401
0
                case Fragment::OR_C: {
1402
0
                    auto& x = subres[0], &z = subres[1];
1403
0
                    return {INVALID, std::move(x.sat) | (z.sat + x.nsat)};
1404
105
                }
1405
8
                case Fragment::OR_D: {
1406
8
                    auto& x = subres[0], &z = subres[1];
1407
8
                    return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
1408
105
                }
1409
223
                case Fragment::OR_I: {
1410
223
                    auto& x = subres[0], &z = subres[1];
1411
223
                    return {(x.nsat + ONE) | (z.nsat + ZERO), (x.sat + ONE) | (z.sat + ZERO)};
1412
105
                }
1413
44
                case Fragment::ANDOR: {
1414
44
                    auto& x = subres[0], &y = subres[1], &z = subres[2];
1415
44
                    return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
1416
105
                }
1417
40
                case Fragment::WRAP_A:
1418
480
                case Fragment::WRAP_S:
1419
972
                case Fragment::WRAP_C:
1420
1.23k
                case Fragment::WRAP_N:
1421
1.23k
                    return std::move(subres[0]);
1422
24
                case Fragment::WRAP_D: {
1423
24
                    auto &x = subres[0];
1424
24
                    return {ZERO, x.sat + ONE};
1425
972
                }
1426
0
                case Fragment::WRAP_J: {
1427
0
                    auto &x = subres[0];
1428
                    // If a dissatisfaction with a nonzero top stack element exists, an alternative dissatisfaction exists.
1429
                    // As the dissatisfaction logic currently doesn't keep track of this nonzeroness property, and thus even
1430
                    // if a dissatisfaction with a top zero element is found, we don't know whether another one with a
1431
                    // nonzero top stack element exists. Make the conservative assumption that whenever the subexpression is weakly
1432
                    // dissatisfiable, this alternative dissatisfaction exists and leads to malleability.
1433
0
                    return {InputStack(ZERO).SetMalleable(x.nsat.available != Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
1434
972
                }
1435
132
                case Fragment::WRAP_V: {
1436
132
                    auto &x = subres[0];
1437
132
                    return {INVALID, std::move(x.sat)};
1438
972
                }
1439
243
                case Fragment::JUST_0: return {EMPTY, INVALID};
1440
0
                case Fragment::JUST_1: return {INVALID, EMPTY};
1441
3.01k
            }
1442
3.01k
            assert(false);
1443
0
            return {INVALID, INVALID};
1444
0
        };
1445
1446
6.89M
        auto tester = [&helper](const Node& node, std::span<InputResult> subres) -> InputResult {
1447
6.89M
            auto ret = helper(node, subres);
1448
1449
            // Do a consistency check between the satisfaction code and the type checker
1450
            // (the actual satisfaction code in ProduceInputHelper does not use GetType)
1451
1452
            // For 'z' nodes, available satisfactions/dissatisfactions must have stack size 0.
1453
6.89M
            if (node.GetType() << "z"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 0);
1454
6.89M
            if (node.GetType() << "z"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 0);
1455
1456
            // For 'o' nodes, available satisfactions/dissatisfactions must have stack size 1.
1457
6.89M
            if (node.GetType() << "o"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 1);
1458
6.89M
            if (node.GetType() << "o"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 1);
1459
1460
            // For 'n' nodes, available satisfactions/dissatisfactions must have stack size 1 or larger. For satisfactions,
1461
            // the top element cannot be 0.
1462
6.89M
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() >= 1);
1463
6.89M
            if (node.GetType() << "n"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() >= 1);
1464
6.89M
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.stack.back().empty());
1465
1466
            // For 'd' nodes, a dissatisfaction must exist, and they must not need a signature. If it is non-malleable,
1467
            // it must be canonical.
1468
6.89M
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1469
6.89M
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(!ret.nsat.has_sig);
1470
6.89M
            if (node.GetType() << "d"_mst && !ret.nsat.malleable) CHECK_NONFATAL(!ret.nsat.non_canon);
1471
1472
            // For 'f'/'s' nodes, dissatisfactions/satisfactions must have a signature.
1473
6.89M
            if (node.GetType() << "f"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.has_sig);
1474
6.89M
            if (node.GetType() << "s"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.has_sig);
1475
1476
            // For non-malleable 'e' nodes, a non-malleable dissatisfaction must exist.
1477
6.89M
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1478
6.89M
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(!ret.nsat.malleable);
1479
1480
            // For 'm' nodes, if a satisfaction exists, it must be non-malleable.
1481
6.89M
            if (node.GetType() << "m"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.malleable);
1482
1483
            // If a non-malleable satisfaction exists, it must be canonical.
1484
6.89M
            if (ret.sat.available != Availability::NO && !ret.sat.malleable) CHECK_NONFATAL(!ret.sat.non_canon);
1485
1486
6.89M
            return ret;
1487
6.89M
        };
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
1446
1.61M
        auto tester = [&helper](const Node& node, std::span<InputResult> subres) -> InputResult {
1447
1.61M
            auto ret = helper(node, subres);
1448
1449
            // Do a consistency check between the satisfaction code and the type checker
1450
            // (the actual satisfaction code in ProduceInputHelper does not use GetType)
1451
1452
            // For 'z' nodes, available satisfactions/dissatisfactions must have stack size 0.
1453
1.61M
            if (node.GetType() << "z"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 0);
1454
1.61M
            if (node.GetType() << "z"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 0);
1455
1456
            // For 'o' nodes, available satisfactions/dissatisfactions must have stack size 1.
1457
1.61M
            if (node.GetType() << "o"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 1);
1458
1.61M
            if (node.GetType() << "o"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 1);
1459
1460
            // For 'n' nodes, available satisfactions/dissatisfactions must have stack size 1 or larger. For satisfactions,
1461
            // the top element cannot be 0.
1462
1.61M
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() >= 1);
1463
1.61M
            if (node.GetType() << "n"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() >= 1);
1464
1.61M
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.stack.back().empty());
1465
1466
            // For 'd' nodes, a dissatisfaction must exist, and they must not need a signature. If it is non-malleable,
1467
            // it must be canonical.
1468
1.61M
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1469
1.61M
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(!ret.nsat.has_sig);
1470
1.61M
            if (node.GetType() << "d"_mst && !ret.nsat.malleable) CHECK_NONFATAL(!ret.nsat.non_canon);
1471
1472
            // For 'f'/'s' nodes, dissatisfactions/satisfactions must have a signature.
1473
1.61M
            if (node.GetType() << "f"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.has_sig);
1474
1.61M
            if (node.GetType() << "s"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.has_sig);
1475
1476
            // For non-malleable 'e' nodes, a non-malleable dissatisfaction must exist.
1477
1.61M
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1478
1.61M
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(!ret.nsat.malleable);
1479
1480
            // For 'm' nodes, if a satisfaction exists, it must be non-malleable.
1481
1.61M
            if (node.GetType() << "m"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.malleable);
1482
1483
            // If a non-malleable satisfaction exists, it must be canonical.
1484
1.61M
            if (ret.sat.available != Availability::NO && !ret.sat.malleable) CHECK_NONFATAL(!ret.sat.non_canon);
1485
1486
1.61M
            return ret;
1487
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
1446
5.27M
        auto tester = [&helper](const Node& node, std::span<InputResult> subres) -> InputResult {
1447
5.27M
            auto ret = helper(node, subres);
1448
1449
            // Do a consistency check between the satisfaction code and the type checker
1450
            // (the actual satisfaction code in ProduceInputHelper does not use GetType)
1451
1452
            // For 'z' nodes, available satisfactions/dissatisfactions must have stack size 0.
1453
5.27M
            if (node.GetType() << "z"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 0);
1454
5.27M
            if (node.GetType() << "z"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 0);
1455
1456
            // For 'o' nodes, available satisfactions/dissatisfactions must have stack size 1.
1457
5.27M
            if (node.GetType() << "o"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 1);
1458
5.27M
            if (node.GetType() << "o"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 1);
1459
1460
            // For 'n' nodes, available satisfactions/dissatisfactions must have stack size 1 or larger. For satisfactions,
1461
            // the top element cannot be 0.
1462
5.27M
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() >= 1);
1463
5.27M
            if (node.GetType() << "n"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() >= 1);
1464
5.27M
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.stack.back().empty());
1465
1466
            // For 'd' nodes, a dissatisfaction must exist, and they must not need a signature. If it is non-malleable,
1467
            // it must be canonical.
1468
5.27M
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1469
5.27M
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(!ret.nsat.has_sig);
1470
5.27M
            if (node.GetType() << "d"_mst && !ret.nsat.malleable) CHECK_NONFATAL(!ret.nsat.non_canon);
1471
1472
            // For 'f'/'s' nodes, dissatisfactions/satisfactions must have a signature.
1473
5.27M
            if (node.GetType() << "f"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.has_sig);
1474
5.27M
            if (node.GetType() << "s"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.has_sig);
1475
1476
            // For non-malleable 'e' nodes, a non-malleable dissatisfaction must exist.
1477
5.27M
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1478
5.27M
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(!ret.nsat.malleable);
1479
1480
            // For 'm' nodes, if a satisfaction exists, it must be non-malleable.
1481
5.27M
            if (node.GetType() << "m"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.malleable);
1482
1483
            // If a non-malleable satisfaction exists, it must be canonical.
1484
5.27M
            if (ret.sat.available != Availability::NO && !ret.sat.malleable) CHECK_NONFATAL(!ret.sat.non_canon);
1485
1486
5.27M
            return ret;
1487
5.27M
        };
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
1446
3.01k
        auto tester = [&helper](const Node& node, std::span<InputResult> subres) -> InputResult {
1447
3.01k
            auto ret = helper(node, subres);
1448
1449
            // Do a consistency check between the satisfaction code and the type checker
1450
            // (the actual satisfaction code in ProduceInputHelper does not use GetType)
1451
1452
            // For 'z' nodes, available satisfactions/dissatisfactions must have stack size 0.
1453
3.01k
            if (node.GetType() << "z"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 0);
1454
3.01k
            if (node.GetType() << "z"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 0);
1455
1456
            // For 'o' nodes, available satisfactions/dissatisfactions must have stack size 1.
1457
3.01k
            if (node.GetType() << "o"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 1);
1458
3.01k
            if (node.GetType() << "o"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 1);
1459
1460
            // For 'n' nodes, available satisfactions/dissatisfactions must have stack size 1 or larger. For satisfactions,
1461
            // the top element cannot be 0.
1462
3.01k
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() >= 1);
1463
3.01k
            if (node.GetType() << "n"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() >= 1);
1464
3.01k
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.stack.back().empty());
1465
1466
            // For 'd' nodes, a dissatisfaction must exist, and they must not need a signature. If it is non-malleable,
1467
            // it must be canonical.
1468
3.01k
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1469
3.01k
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(!ret.nsat.has_sig);
1470
3.01k
            if (node.GetType() << "d"_mst && !ret.nsat.malleable) CHECK_NONFATAL(!ret.nsat.non_canon);
1471
1472
            // For 'f'/'s' nodes, dissatisfactions/satisfactions must have a signature.
1473
3.01k
            if (node.GetType() << "f"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.has_sig);
1474
3.01k
            if (node.GetType() << "s"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.has_sig);
1475
1476
            // For non-malleable 'e' nodes, a non-malleable dissatisfaction must exist.
1477
3.01k
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1478
3.01k
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(!ret.nsat.malleable);
1479
1480
            // For 'm' nodes, if a satisfaction exists, it must be non-malleable.
1481
3.01k
            if (node.GetType() << "m"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.malleable);
1482
1483
            // If a non-malleable satisfaction exists, it must be canonical.
1484
3.01k
            if (ret.sat.available != Availability::NO && !ret.sat.malleable) CHECK_NONFATAL(!ret.sat.non_canon);
1485
1486
3.01k
            return ret;
1487
3.01k
        };
1488
1489
8.09k
        return TreeEval<InputResult>(tester);
1490
8.09k
    }
miniscript_tests.cpp:miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<(anonymous namespace)::Satisfier>((anonymous namespace)::Satisfier const&) const
Line
Count
Source
1245
4.82k
    internal::InputResult ProduceInput(const Ctx& ctx) const {
1246
4.82k
        using namespace internal;
1247
1248
        // Internal function which is invoked for every tree node, constructing satisfaction/dissatisfactions
1249
        // given those of its subnodes.
1250
4.82k
        auto helper = [&ctx](const Node& node, std::span<InputResult> subres) -> InputResult {
1251
4.82k
            switch (node.fragment) {
1252
4.82k
                case Fragment::PK_K: {
1253
4.82k
                    std::vector<unsigned char> sig;
1254
4.82k
                    Availability avail = ctx.Sign(node.keys[0], sig);
1255
4.82k
                    return {ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
1256
4.82k
                }
1257
4.82k
                case Fragment::PK_H: {
1258
4.82k
                    std::vector<unsigned char> key = ctx.ToPKBytes(node.keys[0]), sig;
1259
4.82k
                    Availability avail = ctx.Sign(node.keys[0], sig);
1260
4.82k
                    return {ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
1261
4.82k
                }
1262
4.82k
                case Fragment::MULTI_A: {
1263
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1264
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1265
4.82k
                    std::vector<InputStack> sats = Vector(EMPTY);
1266
4.82k
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1267
                        // Get the signature for the i'th key in reverse order (the signature for the first key needs to
1268
                        // be at the top of the stack, contrary to CHECKMULTISIG's satisfaction).
1269
4.82k
                        std::vector<unsigned char> sig;
1270
4.82k
                        Availability avail = ctx.Sign(node.keys[node.keys.size() - 1 - i], sig);
1271
                        // Compute signature stack for just this key.
1272
4.82k
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1273
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1274
                        // next_sats[j] are equal to either the existing sats[j] + ZERO, or sats[j-1] plus a signature
1275
                        // for the current (i'th) key. The very last element needs all signatures filled.
1276
4.82k
                        std::vector<InputStack> next_sats;
1277
4.82k
                        next_sats.push_back(sats[0] + ZERO);
1278
4.82k
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + ZERO) | (std::move(sats[j - 1]) + sat));
1279
4.82k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1280
                        // Switch over.
1281
4.82k
                        sats = std::move(next_sats);
1282
4.82k
                    }
1283
                    // The dissatisfaction consists of as many empty vectors as there are keys, which is the same as
1284
                    // satisfying 0 keys.
1285
4.82k
                    auto& nsat{sats[0]};
1286
4.82k
                    CHECK_NONFATAL(node.k != 0);
1287
4.82k
                    assert(node.k < sats.size());
1288
4.82k
                    return {std::move(nsat), std::move(sats[node.k])};
1289
4.82k
                }
1290
4.82k
                case Fragment::MULTI: {
1291
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1292
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1293
                    // sats[0] starts off being {0}, due to the CHECKMULTISIG bug that pops off one element too many.
1294
4.82k
                    std::vector<InputStack> sats = Vector(ZERO);
1295
4.82k
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1296
4.82k
                        std::vector<unsigned char> sig;
1297
4.82k
                        Availability avail = ctx.Sign(node.keys[i], sig);
1298
                        // Compute signature stack for just the i'th key.
1299
4.82k
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1300
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1301
                        // next_sats[j] are equal to either the existing sats[j], or sats[j-1] plus a signature for the
1302
                        // current (i'th) key. The very last element needs all signatures filled.
1303
4.82k
                        std::vector<InputStack> next_sats;
1304
4.82k
                        next_sats.push_back(sats[0]);
1305
4.82k
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
1306
4.82k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1307
                        // Switch over.
1308
4.82k
                        sats = std::move(next_sats);
1309
4.82k
                    }
1310
                    // The dissatisfaction consists of k+1 stack elements all equal to 0.
1311
4.82k
                    InputStack nsat = ZERO;
1312
4.82k
                    for (size_t i = 0; i < node.k; ++i) nsat = std::move(nsat) + ZERO;
1313
4.82k
                    assert(node.k < sats.size());
1314
4.82k
                    return {std::move(nsat), std::move(sats[node.k])};
1315
4.82k
                }
1316
4.82k
                case Fragment::THRESH: {
1317
                    // sats[k] represents the best stack that satisfies k out of the *last* i subexpressions.
1318
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1319
                    // sats[0] starts off empty.
1320
4.82k
                    std::vector<InputStack> sats = Vector(EMPTY);
1321
4.82k
                    for (size_t i = 0; i < subres.size(); ++i) {
1322
                        // Introduce an alias for the i'th last satisfaction/dissatisfaction.
1323
4.82k
                        auto& res = subres[subres.size() - i - 1];
1324
                        // Compute the next sats vector: next_sats[0] is sats[0] plus res.nsat (thus containing all dissatisfactions
1325
                        // so far. next_sats[j] is either sats[j] + res.nsat (reusing j earlier satisfactions) or sats[j-1] + res.sat
1326
                        // (reusing j-1 earlier satisfactions plus a new one). The very last next_sats[j] is all satisfactions.
1327
4.82k
                        std::vector<InputStack> next_sats;
1328
4.82k
                        next_sats.push_back(sats[0] + res.nsat);
1329
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));
1330
4.82k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
1331
                        // Switch over.
1332
4.82k
                        sats = std::move(next_sats);
1333
4.82k
                    }
1334
                    // At this point, sats[k].sat is the best satisfaction for the overall thresh() node. The best dissatisfaction
1335
                    // is computed by gathering all sats[i].nsat for i != k.
1336
4.82k
                    InputStack nsat = INVALID;
1337
4.82k
                    for (size_t i = 0; i < sats.size(); ++i) {
1338
                        // i==k is the satisfaction; i==0 is the canonical dissatisfaction;
1339
                        // the rest are non-canonical (a no-signature dissatisfaction - the i=0
1340
                        // form - is always available) and malleable (due to overcompleteness).
1341
                        // Marking the solutions malleable here is not strictly necessary, as they
1342
                        // should already never be picked in non-malleable solutions due to the
1343
                        // availability of the i=0 form.
1344
4.82k
                        if (i != 0 && i != node.k) sats[i].SetMalleable().SetNonCanon();
1345
                        // Include all dissatisfactions (even these non-canonical ones) in nsat.
1346
4.82k
                        if (i != node.k) nsat = std::move(nsat) | std::move(sats[i]);
1347
4.82k
                    }
1348
4.82k
                    assert(node.k < sats.size());
1349
4.82k
                    return {std::move(nsat), std::move(sats[node.k])};
1350
4.82k
                }
1351
4.82k
                case Fragment::OLDER: {
1352
4.82k
                    return {INVALID, ctx.CheckOlder(node.k) ? EMPTY : INVALID};
1353
4.82k
                }
1354
4.82k
                case Fragment::AFTER: {
1355
4.82k
                    return {INVALID, ctx.CheckAfter(node.k) ? EMPTY : INVALID};
1356
4.82k
                }
1357
4.82k
                case Fragment::SHA256: {
1358
4.82k
                    std::vector<unsigned char> preimage;
1359
4.82k
                    Availability avail = ctx.SatSHA256(node.data, preimage);
1360
4.82k
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1361
4.82k
                }
1362
4.82k
                case Fragment::RIPEMD160: {
1363
4.82k
                    std::vector<unsigned char> preimage;
1364
4.82k
                    Availability avail = ctx.SatRIPEMD160(node.data, preimage);
1365
4.82k
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1366
4.82k
                }
1367
4.82k
                case Fragment::HASH256: {
1368
4.82k
                    std::vector<unsigned char> preimage;
1369
4.82k
                    Availability avail = ctx.SatHASH256(node.data, preimage);
1370
4.82k
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1371
4.82k
                }
1372
4.82k
                case Fragment::HASH160: {
1373
4.82k
                    std::vector<unsigned char> preimage;
1374
4.82k
                    Availability avail = ctx.SatHASH160(node.data, preimage);
1375
4.82k
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1376
4.82k
                }
1377
4.82k
                case Fragment::AND_V: {
1378
4.82k
                    auto& x = subres[0], &y = subres[1];
1379
                    // As the dissatisfaction here only consist of a single option, it doesn't
1380
                    // actually need to be listed (it's not required for reasoning about malleability of
1381
                    // other options), and is never required (no valid miniscript relies on the ability
1382
                    // to satisfy the type V left subexpression). It's still listed here for
1383
                    // completeness, as a hypothetical (not currently implemented) satisfier that doesn't
1384
                    // care about malleability might in some cases prefer it still.
1385
4.82k
                    return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
1386
4.82k
                }
1387
4.82k
                case Fragment::AND_B: {
1388
4.82k
                    auto& x = subres[0], &y = subres[1];
1389
                    // Note that it is not strictly necessary to mark the 2nd and 3rd dissatisfaction here
1390
                    // as malleable. While they are definitely malleable, they are also non-canonical due
1391
                    // to the guaranteed existence of a no-signature other dissatisfaction (the 1st)
1392
                    // option. Because of that, the 2nd and 3rd option will never be chosen, even if they
1393
                    // weren't marked as malleable.
1394
4.82k
                    return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
1395
4.82k
                }
1396
4.82k
                case Fragment::OR_B: {
1397
4.82k
                    auto& x = subres[0], &z = subres[1];
1398
                    // The (sat(Z) sat(X)) solution is overcomplete (attacker can change either into dsat).
1399
4.82k
                    return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
1400
4.82k
                }
1401
4.82k
                case Fragment::OR_C: {
1402
4.82k
                    auto& x = subres[0], &z = subres[1];
1403
4.82k
                    return {INVALID, std::move(x.sat) | (z.sat + x.nsat)};
1404
4.82k
                }
1405
4.82k
                case Fragment::OR_D: {
1406
4.82k
                    auto& x = subres[0], &z = subres[1];
1407
4.82k
                    return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
1408
4.82k
                }
1409
4.82k
                case Fragment::OR_I: {
1410
4.82k
                    auto& x = subres[0], &z = subres[1];
1411
4.82k
                    return {(x.nsat + ONE) | (z.nsat + ZERO), (x.sat + ONE) | (z.sat + ZERO)};
1412
4.82k
                }
1413
4.82k
                case Fragment::ANDOR: {
1414
4.82k
                    auto& x = subres[0], &y = subres[1], &z = subres[2];
1415
4.82k
                    return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
1416
4.82k
                }
1417
4.82k
                case Fragment::WRAP_A:
1418
4.82k
                case Fragment::WRAP_S:
1419
4.82k
                case Fragment::WRAP_C:
1420
4.82k
                case Fragment::WRAP_N:
1421
4.82k
                    return std::move(subres[0]);
1422
4.82k
                case Fragment::WRAP_D: {
1423
4.82k
                    auto &x = subres[0];
1424
4.82k
                    return {ZERO, x.sat + ONE};
1425
4.82k
                }
1426
4.82k
                case Fragment::WRAP_J: {
1427
4.82k
                    auto &x = subres[0];
1428
                    // If a dissatisfaction with a nonzero top stack element exists, an alternative dissatisfaction exists.
1429
                    // As the dissatisfaction logic currently doesn't keep track of this nonzeroness property, and thus even
1430
                    // if a dissatisfaction with a top zero element is found, we don't know whether another one with a
1431
                    // nonzero top stack element exists. Make the conservative assumption that whenever the subexpression is weakly
1432
                    // dissatisfiable, this alternative dissatisfaction exists and leads to malleability.
1433
4.82k
                    return {InputStack(ZERO).SetMalleable(x.nsat.available != Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
1434
4.82k
                }
1435
4.82k
                case Fragment::WRAP_V: {
1436
4.82k
                    auto &x = subres[0];
1437
4.82k
                    return {INVALID, std::move(x.sat)};
1438
4.82k
                }
1439
4.82k
                case Fragment::JUST_0: return {EMPTY, INVALID};
1440
4.82k
                case Fragment::JUST_1: return {INVALID, EMPTY};
1441
4.82k
            }
1442
4.82k
            assert(false);
1443
4.82k
            return {INVALID, INVALID};
1444
4.82k
        };
1445
1446
4.82k
        auto tester = [&helper](const Node& node, std::span<InputResult> subres) -> InputResult {
1447
4.82k
            auto ret = helper(node, subres);
1448
1449
            // Do a consistency check between the satisfaction code and the type checker
1450
            // (the actual satisfaction code in ProduceInputHelper does not use GetType)
1451
1452
            // For 'z' nodes, available satisfactions/dissatisfactions must have stack size 0.
1453
4.82k
            if (node.GetType() << "z"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 0);
1454
4.82k
            if (node.GetType() << "z"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 0);
1455
1456
            // For 'o' nodes, available satisfactions/dissatisfactions must have stack size 1.
1457
4.82k
            if (node.GetType() << "o"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 1);
1458
4.82k
            if (node.GetType() << "o"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 1);
1459
1460
            // For 'n' nodes, available satisfactions/dissatisfactions must have stack size 1 or larger. For satisfactions,
1461
            // the top element cannot be 0.
1462
4.82k
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() >= 1);
1463
4.82k
            if (node.GetType() << "n"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() >= 1);
1464
4.82k
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.stack.back().empty());
1465
1466
            // For 'd' nodes, a dissatisfaction must exist, and they must not need a signature. If it is non-malleable,
1467
            // it must be canonical.
1468
4.82k
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1469
4.82k
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(!ret.nsat.has_sig);
1470
4.82k
            if (node.GetType() << "d"_mst && !ret.nsat.malleable) CHECK_NONFATAL(!ret.nsat.non_canon);
1471
1472
            // For 'f'/'s' nodes, dissatisfactions/satisfactions must have a signature.
1473
4.82k
            if (node.GetType() << "f"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.has_sig);
1474
4.82k
            if (node.GetType() << "s"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.has_sig);
1475
1476
            // For non-malleable 'e' nodes, a non-malleable dissatisfaction must exist.
1477
4.82k
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1478
4.82k
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(!ret.nsat.malleable);
1479
1480
            // For 'm' nodes, if a satisfaction exists, it must be non-malleable.
1481
4.82k
            if (node.GetType() << "m"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.malleable);
1482
1483
            // If a non-malleable satisfaction exists, it must be canonical.
1484
4.82k
            if (ret.sat.available != Availability::NO && !ret.sat.malleable) CHECK_NONFATAL(!ret.sat.non_canon);
1485
1486
4.82k
            return ret;
1487
4.82k
        };
1488
1489
4.82k
        return TreeEval<InputResult>(tester);
1490
4.82k
    }
miniscript::internal::InputResult miniscript::Node<XOnlyPubKey>::ProduceInput<TapSatisfier>(TapSatisfier const&) const
Line
Count
Source
1245
3.05k
    internal::InputResult ProduceInput(const Ctx& ctx) const {
1246
3.05k
        using namespace internal;
1247
1248
        // Internal function which is invoked for every tree node, constructing satisfaction/dissatisfactions
1249
        // given those of its subnodes.
1250
3.05k
        auto helper = [&ctx](const Node& node, std::span<InputResult> subres) -> InputResult {
1251
3.05k
            switch (node.fragment) {
1252
3.05k
                case Fragment::PK_K: {
1253
3.05k
                    std::vector<unsigned char> sig;
1254
3.05k
                    Availability avail = ctx.Sign(node.keys[0], sig);
1255
3.05k
                    return {ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
1256
3.05k
                }
1257
3.05k
                case Fragment::PK_H: {
1258
3.05k
                    std::vector<unsigned char> key = ctx.ToPKBytes(node.keys[0]), sig;
1259
3.05k
                    Availability avail = ctx.Sign(node.keys[0], sig);
1260
3.05k
                    return {ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
1261
3.05k
                }
1262
3.05k
                case Fragment::MULTI_A: {
1263
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1264
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1265
3.05k
                    std::vector<InputStack> sats = Vector(EMPTY);
1266
3.05k
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1267
                        // Get the signature for the i'th key in reverse order (the signature for the first key needs to
1268
                        // be at the top of the stack, contrary to CHECKMULTISIG's satisfaction).
1269
3.05k
                        std::vector<unsigned char> sig;
1270
3.05k
                        Availability avail = ctx.Sign(node.keys[node.keys.size() - 1 - i], sig);
1271
                        // Compute signature stack for just this key.
1272
3.05k
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1273
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1274
                        // next_sats[j] are equal to either the existing sats[j] + ZERO, or sats[j-1] plus a signature
1275
                        // for the current (i'th) key. The very last element needs all signatures filled.
1276
3.05k
                        std::vector<InputStack> next_sats;
1277
3.05k
                        next_sats.push_back(sats[0] + ZERO);
1278
3.05k
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + ZERO) | (std::move(sats[j - 1]) + sat));
1279
3.05k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1280
                        // Switch over.
1281
3.05k
                        sats = std::move(next_sats);
1282
3.05k
                    }
1283
                    // The dissatisfaction consists of as many empty vectors as there are keys, which is the same as
1284
                    // satisfying 0 keys.
1285
3.05k
                    auto& nsat{sats[0]};
1286
3.05k
                    CHECK_NONFATAL(node.k != 0);
1287
3.05k
                    assert(node.k < sats.size());
1288
3.05k
                    return {std::move(nsat), std::move(sats[node.k])};
1289
3.05k
                }
1290
3.05k
                case Fragment::MULTI: {
1291
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1292
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1293
                    // sats[0] starts off being {0}, due to the CHECKMULTISIG bug that pops off one element too many.
1294
3.05k
                    std::vector<InputStack> sats = Vector(ZERO);
1295
3.05k
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1296
3.05k
                        std::vector<unsigned char> sig;
1297
3.05k
                        Availability avail = ctx.Sign(node.keys[i], sig);
1298
                        // Compute signature stack for just the i'th key.
1299
3.05k
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1300
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1301
                        // next_sats[j] are equal to either the existing sats[j], or sats[j-1] plus a signature for the
1302
                        // current (i'th) key. The very last element needs all signatures filled.
1303
3.05k
                        std::vector<InputStack> next_sats;
1304
3.05k
                        next_sats.push_back(sats[0]);
1305
3.05k
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
1306
3.05k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1307
                        // Switch over.
1308
3.05k
                        sats = std::move(next_sats);
1309
3.05k
                    }
1310
                    // The dissatisfaction consists of k+1 stack elements all equal to 0.
1311
3.05k
                    InputStack nsat = ZERO;
1312
3.05k
                    for (size_t i = 0; i < node.k; ++i) nsat = std::move(nsat) + ZERO;
1313
3.05k
                    assert(node.k < sats.size());
1314
3.05k
                    return {std::move(nsat), std::move(sats[node.k])};
1315
3.05k
                }
1316
3.05k
                case Fragment::THRESH: {
1317
                    // sats[k] represents the best stack that satisfies k out of the *last* i subexpressions.
1318
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1319
                    // sats[0] starts off empty.
1320
3.05k
                    std::vector<InputStack> sats = Vector(EMPTY);
1321
3.05k
                    for (size_t i = 0; i < subres.size(); ++i) {
1322
                        // Introduce an alias for the i'th last satisfaction/dissatisfaction.
1323
3.05k
                        auto& res = subres[subres.size() - i - 1];
1324
                        // Compute the next sats vector: next_sats[0] is sats[0] plus res.nsat (thus containing all dissatisfactions
1325
                        // so far. next_sats[j] is either sats[j] + res.nsat (reusing j earlier satisfactions) or sats[j-1] + res.sat
1326
                        // (reusing j-1 earlier satisfactions plus a new one). The very last next_sats[j] is all satisfactions.
1327
3.05k
                        std::vector<InputStack> next_sats;
1328
3.05k
                        next_sats.push_back(sats[0] + res.nsat);
1329
3.05k
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + res.nsat) | (std::move(sats[j - 1]) + res.sat));
1330
3.05k
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
1331
                        // Switch over.
1332
3.05k
                        sats = std::move(next_sats);
1333
3.05k
                    }
1334
                    // At this point, sats[k].sat is the best satisfaction for the overall thresh() node. The best dissatisfaction
1335
                    // is computed by gathering all sats[i].nsat for i != k.
1336
3.05k
                    InputStack nsat = INVALID;
1337
3.05k
                    for (size_t i = 0; i < sats.size(); ++i) {
1338
                        // i==k is the satisfaction; i==0 is the canonical dissatisfaction;
1339
                        // the rest are non-canonical (a no-signature dissatisfaction - the i=0
1340
                        // form - is always available) and malleable (due to overcompleteness).
1341
                        // Marking the solutions malleable here is not strictly necessary, as they
1342
                        // should already never be picked in non-malleable solutions due to the
1343
                        // availability of the i=0 form.
1344
3.05k
                        if (i != 0 && i != node.k) sats[i].SetMalleable().SetNonCanon();
1345
                        // Include all dissatisfactions (even these non-canonical ones) in nsat.
1346
3.05k
                        if (i != node.k) nsat = std::move(nsat) | std::move(sats[i]);
1347
3.05k
                    }
1348
3.05k
                    assert(node.k < sats.size());
1349
3.05k
                    return {std::move(nsat), std::move(sats[node.k])};
1350
3.05k
                }
1351
3.05k
                case Fragment::OLDER: {
1352
3.05k
                    return {INVALID, ctx.CheckOlder(node.k) ? EMPTY : INVALID};
1353
3.05k
                }
1354
3.05k
                case Fragment::AFTER: {
1355
3.05k
                    return {INVALID, ctx.CheckAfter(node.k) ? EMPTY : INVALID};
1356
3.05k
                }
1357
3.05k
                case Fragment::SHA256: {
1358
3.05k
                    std::vector<unsigned char> preimage;
1359
3.05k
                    Availability avail = ctx.SatSHA256(node.data, preimage);
1360
3.05k
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1361
3.05k
                }
1362
3.05k
                case Fragment::RIPEMD160: {
1363
3.05k
                    std::vector<unsigned char> preimage;
1364
3.05k
                    Availability avail = ctx.SatRIPEMD160(node.data, preimage);
1365
3.05k
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1366
3.05k
                }
1367
3.05k
                case Fragment::HASH256: {
1368
3.05k
                    std::vector<unsigned char> preimage;
1369
3.05k
                    Availability avail = ctx.SatHASH256(node.data, preimage);
1370
3.05k
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1371
3.05k
                }
1372
3.05k
                case Fragment::HASH160: {
1373
3.05k
                    std::vector<unsigned char> preimage;
1374
3.05k
                    Availability avail = ctx.SatHASH160(node.data, preimage);
1375
3.05k
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1376
3.05k
                }
1377
3.05k
                case Fragment::AND_V: {
1378
3.05k
                    auto& x = subres[0], &y = subres[1];
1379
                    // As the dissatisfaction here only consist of a single option, it doesn't
1380
                    // actually need to be listed (it's not required for reasoning about malleability of
1381
                    // other options), and is never required (no valid miniscript relies on the ability
1382
                    // to satisfy the type V left subexpression). It's still listed here for
1383
                    // completeness, as a hypothetical (not currently implemented) satisfier that doesn't
1384
                    // care about malleability might in some cases prefer it still.
1385
3.05k
                    return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
1386
3.05k
                }
1387
3.05k
                case Fragment::AND_B: {
1388
3.05k
                    auto& x = subres[0], &y = subres[1];
1389
                    // Note that it is not strictly necessary to mark the 2nd and 3rd dissatisfaction here
1390
                    // as malleable. While they are definitely malleable, they are also non-canonical due
1391
                    // to the guaranteed existence of a no-signature other dissatisfaction (the 1st)
1392
                    // option. Because of that, the 2nd and 3rd option will never be chosen, even if they
1393
                    // weren't marked as malleable.
1394
3.05k
                    return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
1395
3.05k
                }
1396
3.05k
                case Fragment::OR_B: {
1397
3.05k
                    auto& x = subres[0], &z = subres[1];
1398
                    // The (sat(Z) sat(X)) solution is overcomplete (attacker can change either into dsat).
1399
3.05k
                    return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
1400
3.05k
                }
1401
3.05k
                case Fragment::OR_C: {
1402
3.05k
                    auto& x = subres[0], &z = subres[1];
1403
3.05k
                    return {INVALID, std::move(x.sat) | (z.sat + x.nsat)};
1404
3.05k
                }
1405
3.05k
                case Fragment::OR_D: {
1406
3.05k
                    auto& x = subres[0], &z = subres[1];
1407
3.05k
                    return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
1408
3.05k
                }
1409
3.05k
                case Fragment::OR_I: {
1410
3.05k
                    auto& x = subres[0], &z = subres[1];
1411
3.05k
                    return {(x.nsat + ONE) | (z.nsat + ZERO), (x.sat + ONE) | (z.sat + ZERO)};
1412
3.05k
                }
1413
3.05k
                case Fragment::ANDOR: {
1414
3.05k
                    auto& x = subres[0], &y = subres[1], &z = subres[2];
1415
3.05k
                    return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
1416
3.05k
                }
1417
3.05k
                case Fragment::WRAP_A:
1418
3.05k
                case Fragment::WRAP_S:
1419
3.05k
                case Fragment::WRAP_C:
1420
3.05k
                case Fragment::WRAP_N:
1421
3.05k
                    return std::move(subres[0]);
1422
3.05k
                case Fragment::WRAP_D: {
1423
3.05k
                    auto &x = subres[0];
1424
3.05k
                    return {ZERO, x.sat + ONE};
1425
3.05k
                }
1426
3.05k
                case Fragment::WRAP_J: {
1427
3.05k
                    auto &x = subres[0];
1428
                    // If a dissatisfaction with a nonzero top stack element exists, an alternative dissatisfaction exists.
1429
                    // As the dissatisfaction logic currently doesn't keep track of this nonzeroness property, and thus even
1430
                    // if a dissatisfaction with a top zero element is found, we don't know whether another one with a
1431
                    // nonzero top stack element exists. Make the conservative assumption that whenever the subexpression is weakly
1432
                    // dissatisfiable, this alternative dissatisfaction exists and leads to malleability.
1433
3.05k
                    return {InputStack(ZERO).SetMalleable(x.nsat.available != Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
1434
3.05k
                }
1435
3.05k
                case Fragment::WRAP_V: {
1436
3.05k
                    auto &x = subres[0];
1437
3.05k
                    return {INVALID, std::move(x.sat)};
1438
3.05k
                }
1439
3.05k
                case Fragment::JUST_0: return {EMPTY, INVALID};
1440
3.05k
                case Fragment::JUST_1: return {INVALID, EMPTY};
1441
3.05k
            }
1442
3.05k
            assert(false);
1443
3.05k
            return {INVALID, INVALID};
1444
3.05k
        };
1445
1446
3.05k
        auto tester = [&helper](const Node& node, std::span<InputResult> subres) -> InputResult {
1447
3.05k
            auto ret = helper(node, subres);
1448
1449
            // Do a consistency check between the satisfaction code and the type checker
1450
            // (the actual satisfaction code in ProduceInputHelper does not use GetType)
1451
1452
            // For 'z' nodes, available satisfactions/dissatisfactions must have stack size 0.
1453
3.05k
            if (node.GetType() << "z"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 0);
1454
3.05k
            if (node.GetType() << "z"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 0);
1455
1456
            // For 'o' nodes, available satisfactions/dissatisfactions must have stack size 1.
1457
3.05k
            if (node.GetType() << "o"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 1);
1458
3.05k
            if (node.GetType() << "o"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 1);
1459
1460
            // For 'n' nodes, available satisfactions/dissatisfactions must have stack size 1 or larger. For satisfactions,
1461
            // the top element cannot be 0.
1462
3.05k
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() >= 1);
1463
3.05k
            if (node.GetType() << "n"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() >= 1);
1464
3.05k
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.stack.back().empty());
1465
1466
            // For 'd' nodes, a dissatisfaction must exist, and they must not need a signature. If it is non-malleable,
1467
            // it must be canonical.
1468
3.05k
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1469
3.05k
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(!ret.nsat.has_sig);
1470
3.05k
            if (node.GetType() << "d"_mst && !ret.nsat.malleable) CHECK_NONFATAL(!ret.nsat.non_canon);
1471
1472
            // For 'f'/'s' nodes, dissatisfactions/satisfactions must have a signature.
1473
3.05k
            if (node.GetType() << "f"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.has_sig);
1474
3.05k
            if (node.GetType() << "s"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.has_sig);
1475
1476
            // For non-malleable 'e' nodes, a non-malleable dissatisfaction must exist.
1477
3.05k
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1478
3.05k
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(!ret.nsat.malleable);
1479
1480
            // For 'm' nodes, if a satisfaction exists, it must be non-malleable.
1481
3.05k
            if (node.GetType() << "m"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.malleable);
1482
1483
            // If a non-malleable satisfaction exists, it must be canonical.
1484
3.05k
            if (ret.sat.available != Availability::NO && !ret.sat.malleable) CHECK_NONFATAL(!ret.sat.non_canon);
1485
1486
3.05k
            return ret;
1487
3.05k
        };
1488
1489
3.05k
        return TreeEval<InputResult>(tester);
1490
3.05k
    }
miniscript::internal::InputResult miniscript::Node<CPubKey>::ProduceInput<WshSatisfier>(WshSatisfier const&) const
Line
Count
Source
1245
213
    internal::InputResult ProduceInput(const Ctx& ctx) const {
1246
213
        using namespace internal;
1247
1248
        // Internal function which is invoked for every tree node, constructing satisfaction/dissatisfactions
1249
        // given those of its subnodes.
1250
213
        auto helper = [&ctx](const Node& node, std::span<InputResult> subres) -> InputResult {
1251
213
            switch (node.fragment) {
1252
213
                case Fragment::PK_K: {
1253
213
                    std::vector<unsigned char> sig;
1254
213
                    Availability avail = ctx.Sign(node.keys[0], sig);
1255
213
                    return {ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
1256
213
                }
1257
213
                case Fragment::PK_H: {
1258
213
                    std::vector<unsigned char> key = ctx.ToPKBytes(node.keys[0]), sig;
1259
213
                    Availability avail = ctx.Sign(node.keys[0], sig);
1260
213
                    return {ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
1261
213
                }
1262
213
                case Fragment::MULTI_A: {
1263
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1264
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1265
213
                    std::vector<InputStack> sats = Vector(EMPTY);
1266
213
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1267
                        // Get the signature for the i'th key in reverse order (the signature for the first key needs to
1268
                        // be at the top of the stack, contrary to CHECKMULTISIG's satisfaction).
1269
213
                        std::vector<unsigned char> sig;
1270
213
                        Availability avail = ctx.Sign(node.keys[node.keys.size() - 1 - i], sig);
1271
                        // Compute signature stack for just this key.
1272
213
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1273
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1274
                        // next_sats[j] are equal to either the existing sats[j] + ZERO, or sats[j-1] plus a signature
1275
                        // for the current (i'th) key. The very last element needs all signatures filled.
1276
213
                        std::vector<InputStack> next_sats;
1277
213
                        next_sats.push_back(sats[0] + ZERO);
1278
213
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + ZERO) | (std::move(sats[j - 1]) + sat));
1279
213
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1280
                        // Switch over.
1281
213
                        sats = std::move(next_sats);
1282
213
                    }
1283
                    // The dissatisfaction consists of as many empty vectors as there are keys, which is the same as
1284
                    // satisfying 0 keys.
1285
213
                    auto& nsat{sats[0]};
1286
213
                    CHECK_NONFATAL(node.k != 0);
1287
213
                    assert(node.k < sats.size());
1288
213
                    return {std::move(nsat), std::move(sats[node.k])};
1289
213
                }
1290
213
                case Fragment::MULTI: {
1291
                    // sats[j] represents the best stack containing j valid signatures (out of the first i keys).
1292
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1293
                    // sats[0] starts off being {0}, due to the CHECKMULTISIG bug that pops off one element too many.
1294
213
                    std::vector<InputStack> sats = Vector(ZERO);
1295
213
                    for (size_t i = 0; i < node.keys.size(); ++i) {
1296
213
                        std::vector<unsigned char> sig;
1297
213
                        Availability avail = ctx.Sign(node.keys[i], sig);
1298
                        // Compute signature stack for just the i'th key.
1299
213
                        auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1300
                        // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further
1301
                        // next_sats[j] are equal to either the existing sats[j], or sats[j-1] plus a signature for the
1302
                        // current (i'th) key. The very last element needs all signatures filled.
1303
213
                        std::vector<InputStack> next_sats;
1304
213
                        next_sats.push_back(sats[0]);
1305
213
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
1306
213
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1307
                        // Switch over.
1308
213
                        sats = std::move(next_sats);
1309
213
                    }
1310
                    // The dissatisfaction consists of k+1 stack elements all equal to 0.
1311
213
                    InputStack nsat = ZERO;
1312
213
                    for (size_t i = 0; i < node.k; ++i) nsat = std::move(nsat) + ZERO;
1313
213
                    assert(node.k < sats.size());
1314
213
                    return {std::move(nsat), std::move(sats[node.k])};
1315
213
                }
1316
213
                case Fragment::THRESH: {
1317
                    // sats[k] represents the best stack that satisfies k out of the *last* i subexpressions.
1318
                    // In the loop below, these stacks are built up using a dynamic programming approach.
1319
                    // sats[0] starts off empty.
1320
213
                    std::vector<InputStack> sats = Vector(EMPTY);
1321
213
                    for (size_t i = 0; i < subres.size(); ++i) {
1322
                        // Introduce an alias for the i'th last satisfaction/dissatisfaction.
1323
213
                        auto& res = subres[subres.size() - i - 1];
1324
                        // Compute the next sats vector: next_sats[0] is sats[0] plus res.nsat (thus containing all dissatisfactions
1325
                        // so far. next_sats[j] is either sats[j] + res.nsat (reusing j earlier satisfactions) or sats[j-1] + res.sat
1326
                        // (reusing j-1 earlier satisfactions plus a new one). The very last next_sats[j] is all satisfactions.
1327
213
                        std::vector<InputStack> next_sats;
1328
213
                        next_sats.push_back(sats[0] + res.nsat);
1329
213
                        for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + res.nsat) | (std::move(sats[j - 1]) + res.sat));
1330
213
                        next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
1331
                        // Switch over.
1332
213
                        sats = std::move(next_sats);
1333
213
                    }
1334
                    // At this point, sats[k].sat is the best satisfaction for the overall thresh() node. The best dissatisfaction
1335
                    // is computed by gathering all sats[i].nsat for i != k.
1336
213
                    InputStack nsat = INVALID;
1337
213
                    for (size_t i = 0; i < sats.size(); ++i) {
1338
                        // i==k is the satisfaction; i==0 is the canonical dissatisfaction;
1339
                        // the rest are non-canonical (a no-signature dissatisfaction - the i=0
1340
                        // form - is always available) and malleable (due to overcompleteness).
1341
                        // Marking the solutions malleable here is not strictly necessary, as they
1342
                        // should already never be picked in non-malleable solutions due to the
1343
                        // availability of the i=0 form.
1344
213
                        if (i != 0 && i != node.k) sats[i].SetMalleable().SetNonCanon();
1345
                        // Include all dissatisfactions (even these non-canonical ones) in nsat.
1346
213
                        if (i != node.k) nsat = std::move(nsat) | std::move(sats[i]);
1347
213
                    }
1348
213
                    assert(node.k < sats.size());
1349
213
                    return {std::move(nsat), std::move(sats[node.k])};
1350
213
                }
1351
213
                case Fragment::OLDER: {
1352
213
                    return {INVALID, ctx.CheckOlder(node.k) ? EMPTY : INVALID};
1353
213
                }
1354
213
                case Fragment::AFTER: {
1355
213
                    return {INVALID, ctx.CheckAfter(node.k) ? EMPTY : INVALID};
1356
213
                }
1357
213
                case Fragment::SHA256: {
1358
213
                    std::vector<unsigned char> preimage;
1359
213
                    Availability avail = ctx.SatSHA256(node.data, preimage);
1360
213
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1361
213
                }
1362
213
                case Fragment::RIPEMD160: {
1363
213
                    std::vector<unsigned char> preimage;
1364
213
                    Availability avail = ctx.SatRIPEMD160(node.data, preimage);
1365
213
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1366
213
                }
1367
213
                case Fragment::HASH256: {
1368
213
                    std::vector<unsigned char> preimage;
1369
213
                    Availability avail = ctx.SatHASH256(node.data, preimage);
1370
213
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1371
213
                }
1372
213
                case Fragment::HASH160: {
1373
213
                    std::vector<unsigned char> preimage;
1374
213
                    Availability avail = ctx.SatHASH160(node.data, preimage);
1375
213
                    return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1376
213
                }
1377
213
                case Fragment::AND_V: {
1378
213
                    auto& x = subres[0], &y = subres[1];
1379
                    // As the dissatisfaction here only consist of a single option, it doesn't
1380
                    // actually need to be listed (it's not required for reasoning about malleability of
1381
                    // other options), and is never required (no valid miniscript relies on the ability
1382
                    // to satisfy the type V left subexpression). It's still listed here for
1383
                    // completeness, as a hypothetical (not currently implemented) satisfier that doesn't
1384
                    // care about malleability might in some cases prefer it still.
1385
213
                    return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
1386
213
                }
1387
213
                case Fragment::AND_B: {
1388
213
                    auto& x = subres[0], &y = subres[1];
1389
                    // Note that it is not strictly necessary to mark the 2nd and 3rd dissatisfaction here
1390
                    // as malleable. While they are definitely malleable, they are also non-canonical due
1391
                    // to the guaranteed existence of a no-signature other dissatisfaction (the 1st)
1392
                    // option. Because of that, the 2nd and 3rd option will never be chosen, even if they
1393
                    // weren't marked as malleable.
1394
213
                    return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
1395
213
                }
1396
213
                case Fragment::OR_B: {
1397
213
                    auto& x = subres[0], &z = subres[1];
1398
                    // The (sat(Z) sat(X)) solution is overcomplete (attacker can change either into dsat).
1399
213
                    return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
1400
213
                }
1401
213
                case Fragment::OR_C: {
1402
213
                    auto& x = subres[0], &z = subres[1];
1403
213
                    return {INVALID, std::move(x.sat) | (z.sat + x.nsat)};
1404
213
                }
1405
213
                case Fragment::OR_D: {
1406
213
                    auto& x = subres[0], &z = subres[1];
1407
213
                    return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
1408
213
                }
1409
213
                case Fragment::OR_I: {
1410
213
                    auto& x = subres[0], &z = subres[1];
1411
213
                    return {(x.nsat + ONE) | (z.nsat + ZERO), (x.sat + ONE) | (z.sat + ZERO)};
1412
213
                }
1413
213
                case Fragment::ANDOR: {
1414
213
                    auto& x = subres[0], &y = subres[1], &z = subres[2];
1415
213
                    return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
1416
213
                }
1417
213
                case Fragment::WRAP_A:
1418
213
                case Fragment::WRAP_S:
1419
213
                case Fragment::WRAP_C:
1420
213
                case Fragment::WRAP_N:
1421
213
                    return std::move(subres[0]);
1422
213
                case Fragment::WRAP_D: {
1423
213
                    auto &x = subres[0];
1424
213
                    return {ZERO, x.sat + ONE};
1425
213
                }
1426
213
                case Fragment::WRAP_J: {
1427
213
                    auto &x = subres[0];
1428
                    // If a dissatisfaction with a nonzero top stack element exists, an alternative dissatisfaction exists.
1429
                    // As the dissatisfaction logic currently doesn't keep track of this nonzeroness property, and thus even
1430
                    // if a dissatisfaction with a top zero element is found, we don't know whether another one with a
1431
                    // nonzero top stack element exists. Make the conservative assumption that whenever the subexpression is weakly
1432
                    // dissatisfiable, this alternative dissatisfaction exists and leads to malleability.
1433
213
                    return {InputStack(ZERO).SetMalleable(x.nsat.available != Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
1434
213
                }
1435
213
                case Fragment::WRAP_V: {
1436
213
                    auto &x = subres[0];
1437
213
                    return {INVALID, std::move(x.sat)};
1438
213
                }
1439
213
                case Fragment::JUST_0: return {EMPTY, INVALID};
1440
213
                case Fragment::JUST_1: return {INVALID, EMPTY};
1441
213
            }
1442
213
            assert(false);
1443
213
            return {INVALID, INVALID};
1444
213
        };
1445
1446
213
        auto tester = [&helper](const Node& node, std::span<InputResult> subres) -> InputResult {
1447
213
            auto ret = helper(node, subres);
1448
1449
            // Do a consistency check between the satisfaction code and the type checker
1450
            // (the actual satisfaction code in ProduceInputHelper does not use GetType)
1451
1452
            // For 'z' nodes, available satisfactions/dissatisfactions must have stack size 0.
1453
213
            if (node.GetType() << "z"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 0);
1454
213
            if (node.GetType() << "z"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 0);
1455
1456
            // For 'o' nodes, available satisfactions/dissatisfactions must have stack size 1.
1457
213
            if (node.GetType() << "o"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() == 1);
1458
213
            if (node.GetType() << "o"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() == 1);
1459
1460
            // For 'n' nodes, available satisfactions/dissatisfactions must have stack size 1 or larger. For satisfactions,
1461
            // the top element cannot be 0.
1462
213
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.stack.size() >= 1);
1463
213
            if (node.GetType() << "n"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.stack.size() >= 1);
1464
213
            if (node.GetType() << "n"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.stack.back().empty());
1465
1466
            // For 'd' nodes, a dissatisfaction must exist, and they must not need a signature. If it is non-malleable,
1467
            // it must be canonical.
1468
213
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1469
213
            if (node.GetType() << "d"_mst) CHECK_NONFATAL(!ret.nsat.has_sig);
1470
213
            if (node.GetType() << "d"_mst && !ret.nsat.malleable) CHECK_NONFATAL(!ret.nsat.non_canon);
1471
1472
            // For 'f'/'s' nodes, dissatisfactions/satisfactions must have a signature.
1473
213
            if (node.GetType() << "f"_mst && ret.nsat.available != Availability::NO) CHECK_NONFATAL(ret.nsat.has_sig);
1474
213
            if (node.GetType() << "s"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(ret.sat.has_sig);
1475
1476
            // For non-malleable 'e' nodes, a non-malleable dissatisfaction must exist.
1477
213
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(ret.nsat.available != Availability::NO);
1478
213
            if (node.GetType() << "me"_mst) CHECK_NONFATAL(!ret.nsat.malleable);
1479
1480
            // For 'm' nodes, if a satisfaction exists, it must be non-malleable.
1481
213
            if (node.GetType() << "m"_mst && ret.sat.available != Availability::NO) CHECK_NONFATAL(!ret.sat.malleable);
1482
1483
            // If a non-malleable satisfaction exists, it must be canonical.
1484
213
            if (ret.sat.available != Availability::NO && !ret.sat.malleable) CHECK_NONFATAL(!ret.sat.non_canon);
1485
1486
213
            return ret;
1487
213
        };
1488
1489
213
        return TreeEval<InputResult>(tester);
1490
213
    }
1491
1492
public:
1493
    /** Update duplicate key information in this Node.
1494
     *
1495
     * This uses a custom key comparator provided by the context in order to still detect duplicates
1496
     * for more complicated types.
1497
     */
1498
    template<typename Ctx> void DuplicateKeyCheck(const Ctx& ctx) const
1499
4.37k
    {
1500
        // We cannot use a lambda here, as lambdas are non assignable, and the set operations
1501
        // below require moving the comparators around.
1502
4.37k
        struct Comp {
1503
4.37k
            const Ctx* ctx_ptr;
1504
6.30M
            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
1504
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
1504
995k
            Comp(const Ctx& ctx) : ctx_ptr(&ctx) {}
void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const::Comp::Comp(TapSatisfier const&)
Line
Count
Source
1504
5.27M
            Comp(const Ctx& ctx) : ctx_ptr(&ctx) {}
void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const::Comp::Comp(WshSatisfier const&)
Line
Count
Source
1504
3.01k
            Comp(const Ctx& ctx) : ctx_ptr(&ctx) {}
1505
295k
            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
1505
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
1505
4.35k
            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
1505
282k
            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
1505
1.00k
            bool operator()(const Key& a, const Key& b) const { return ctx_ptr->KeyCompare(a, b); }
1506
4.37k
        };
1507
1508
        // state in the recursive computation:
1509
        // - std::nullopt means "this node has duplicates"
1510
        // - an std::set means "this node has no duplicate keys, and they are: ...".
1511
4.37k
        using keyset = std::set<Key, Comp>;
1512
4.37k
        using state = std::optional<keyset>;
1513
1514
6.30M
        auto upfn = [&ctx](const Node& node, std::span<state> subs) -> state {
1515
            // If this node is already known to have duplicates, nothing left to do.
1516
6.30M
            if (node.has_duplicate_keys.has_value() && *node.has_duplicate_keys) return {};
1517
1518
            // Check if one of the children is already known to have duplicates.
1519
6.30M
            for (auto& sub : subs) {
1520
6.29M
                if (!sub.has_value()) {
1521
0
                    node.has_duplicate_keys = true;
1522
0
                    return {};
1523
0
                }
1524
6.29M
            }
1525
1526
            // Start building the set of keys involved in this node and children.
1527
            // Start by keys in this node directly.
1528
6.30M
            size_t keys_count = node.keys.size();
1529
6.30M
            keyset key_set{node.keys.begin(), node.keys.end(), Comp(ctx)};
1530
6.30M
            if (key_set.size() != keys_count) {
1531
                // It already has duplicates; bail out.
1532
89
                node.has_duplicate_keys = true;
1533
89
                return {};
1534
89
            }
1535
1536
            // Merge the keys from the children into this set.
1537
6.30M
            for (auto& sub : subs) {
1538
6.29M
                keys_count += sub->size();
1539
                // Small optimization: std::set::merge is linear in the size of the second arg but
1540
                // logarithmic in the size of the first.
1541
6.29M
                if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1542
6.29M
                key_set.merge(*sub);
1543
6.29M
                if (key_set.size() != keys_count) {
1544
8
                    node.has_duplicate_keys = true;
1545
8
                    return {};
1546
8
                }
1547
6.29M
            }
1548
1549
6.30M
            node.has_duplicate_keys = false;
1550
6.30M
            return key_set;
1551
6.30M
        };
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
1514
23.2k
        auto upfn = [&ctx](const Node& node, std::span<state> subs) -> state {
1515
            // If this node is already known to have duplicates, nothing left to do.
1516
23.2k
            if (node.has_duplicate_keys.has_value() && *node.has_duplicate_keys) return {};
1517
1518
            // Check if one of the children is already known to have duplicates.
1519
23.2k
            for (auto& sub : subs) {
1520
22.9k
                if (!sub.has_value()) {
1521
0
                    node.has_duplicate_keys = true;
1522
0
                    return {};
1523
0
                }
1524
22.9k
            }
1525
1526
            // Start building the set of keys involved in this node and children.
1527
            // Start by keys in this node directly.
1528
23.2k
            size_t keys_count = node.keys.size();
1529
23.2k
            keyset key_set{node.keys.begin(), node.keys.end(), Comp(ctx)};
1530
23.2k
            if (key_set.size() != keys_count) {
1531
                // It already has duplicates; bail out.
1532
0
                node.has_duplicate_keys = true;
1533
0
                return {};
1534
0
            }
1535
1536
            // Merge the keys from the children into this set.
1537
23.2k
            for (auto& sub : subs) {
1538
22.9k
                keys_count += sub->size();
1539
                // Small optimization: std::set::merge is linear in the size of the second arg but
1540
                // logarithmic in the size of the first.
1541
22.9k
                if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1542
22.9k
                key_set.merge(*sub);
1543
22.9k
                if (key_set.size() != keys_count) {
1544
6
                    node.has_duplicate_keys = true;
1545
6
                    return {};
1546
6
                }
1547
22.9k
            }
1548
1549
23.2k
            node.has_duplicate_keys = false;
1550
23.2k
            return key_set;
1551
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
1514
995k
        auto upfn = [&ctx](const Node& node, std::span<state> subs) -> state {
1515
            // If this node is already known to have duplicates, nothing left to do.
1516
995k
            if (node.has_duplicate_keys.has_value() && *node.has_duplicate_keys) return {};
1517
1518
            // Check if one of the children is already known to have duplicates.
1519
995k
            for (auto& sub : subs) {
1520
994k
                if (!sub.has_value()) {
1521
0
                    node.has_duplicate_keys = true;
1522
0
                    return {};
1523
0
                }
1524
994k
            }
1525
1526
            // Start building the set of keys involved in this node and children.
1527
            // Start by keys in this node directly.
1528
995k
            size_t keys_count = node.keys.size();
1529
995k
            keyset key_set{node.keys.begin(), node.keys.end(), Comp(ctx)};
1530
995k
            if (key_set.size() != keys_count) {
1531
                // It already has duplicates; bail out.
1532
0
                node.has_duplicate_keys = true;
1533
0
                return {};
1534
0
            }
1535
1536
            // Merge the keys from the children into this set.
1537
995k
            for (auto& sub : subs) {
1538
994k
                keys_count += sub->size();
1539
                // Small optimization: std::set::merge is linear in the size of the second arg but
1540
                // logarithmic in the size of the first.
1541
994k
                if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1542
994k
                key_set.merge(*sub);
1543
994k
                if (key_set.size() != keys_count) {
1544
2
                    node.has_duplicate_keys = true;
1545
2
                    return {};
1546
2
                }
1547
994k
            }
1548
1549
995k
            node.has_duplicate_keys = false;
1550
995k
            return key_set;
1551
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
1514
5.27M
        auto upfn = [&ctx](const Node& node, std::span<state> subs) -> state {
1515
            // If this node is already known to have duplicates, nothing left to do.
1516
5.27M
            if (node.has_duplicate_keys.has_value() && *node.has_duplicate_keys) return {};
1517
1518
            // Check if one of the children is already known to have duplicates.
1519
5.27M
            for (auto& sub : subs) {
1520
5.27M
                if (!sub.has_value()) {
1521
0
                    node.has_duplicate_keys = true;
1522
0
                    return {};
1523
0
                }
1524
5.27M
            }
1525
1526
            // Start building the set of keys involved in this node and children.
1527
            // Start by keys in this node directly.
1528
5.27M
            size_t keys_count = node.keys.size();
1529
5.27M
            keyset key_set{node.keys.begin(), node.keys.end(), Comp(ctx)};
1530
5.27M
            if (key_set.size() != keys_count) {
1531
                // It already has duplicates; bail out.
1532
89
                node.has_duplicate_keys = true;
1533
89
                return {};
1534
89
            }
1535
1536
            // Merge the keys from the children into this set.
1537
5.27M
            for (auto& sub : subs) {
1538
5.27M
                keys_count += sub->size();
1539
                // Small optimization: std::set::merge is linear in the size of the second arg but
1540
                // logarithmic in the size of the first.
1541
5.27M
                if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1542
5.27M
                key_set.merge(*sub);
1543
5.27M
                if (key_set.size() != keys_count) {
1544
0
                    node.has_duplicate_keys = true;
1545
0
                    return {};
1546
0
                }
1547
5.27M
            }
1548
1549
5.27M
            node.has_duplicate_keys = false;
1550
5.27M
            return key_set;
1551
5.27M
        };
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
1514
3.01k
        auto upfn = [&ctx](const Node& node, std::span<state> subs) -> state {
1515
            // If this node is already known to have duplicates, nothing left to do.
1516
3.01k
            if (node.has_duplicate_keys.has_value() && *node.has_duplicate_keys) return {};
1517
1518
            // Check if one of the children is already known to have duplicates.
1519
3.01k
            for (auto& sub : subs) {
1520
2.79k
                if (!sub.has_value()) {
1521
0
                    node.has_duplicate_keys = true;
1522
0
                    return {};
1523
0
                }
1524
2.79k
            }
1525
1526
            // Start building the set of keys involved in this node and children.
1527
            // Start by keys in this node directly.
1528
3.01k
            size_t keys_count = node.keys.size();
1529
3.01k
            keyset key_set{node.keys.begin(), node.keys.end(), Comp(ctx)};
1530
3.01k
            if (key_set.size() != keys_count) {
1531
                // It already has duplicates; bail out.
1532
0
                node.has_duplicate_keys = true;
1533
0
                return {};
1534
0
            }
1535
1536
            // Merge the keys from the children into this set.
1537
3.01k
            for (auto& sub : subs) {
1538
2.79k
                keys_count += sub->size();
1539
                // Small optimization: std::set::merge is linear in the size of the second arg but
1540
                // logarithmic in the size of the first.
1541
2.79k
                if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1542
2.79k
                key_set.merge(*sub);
1543
2.79k
                if (key_set.size() != keys_count) {
1544
0
                    node.has_duplicate_keys = true;
1545
0
                    return {};
1546
0
                }
1547
2.79k
            }
1548
1549
3.01k
            node.has_duplicate_keys = false;
1550
3.01k
            return key_set;
1551
3.01k
        };
1552
1553
4.37k
        TreeEval<state>(upfn);
1554
4.37k
    }
miniscript_tests.cpp:void miniscript::Node<CPubKey>::DuplicateKeyCheck<(anonymous namespace)::KeyConverter>((anonymous namespace)::KeyConverter const&) const
Line
Count
Source
1499
313
    {
1500
        // We cannot use a lambda here, as lambdas are non assignable, and the set operations
1501
        // below require moving the comparators around.
1502
313
        struct Comp {
1503
313
            const Ctx* ctx_ptr;
1504
313
            Comp(const Ctx& ctx) : ctx_ptr(&ctx) {}
1505
313
            bool operator()(const Key& a, const Key& b) const { return ctx_ptr->KeyCompare(a, b); }
1506
313
        };
1507
1508
        // state in the recursive computation:
1509
        // - std::nullopt means "this node has duplicates"
1510
        // - an std::set means "this node has no duplicate keys, and they are: ...".
1511
313
        using keyset = std::set<Key, Comp>;
1512
313
        using state = std::optional<keyset>;
1513
1514
313
        auto upfn = [&ctx](const Node& node, std::span<state> subs) -> state {
1515
            // If this node is already known to have duplicates, nothing left to do.
1516
313
            if (node.has_duplicate_keys.has_value() && *node.has_duplicate_keys) return {};
1517
1518
            // Check if one of the children is already known to have duplicates.
1519
313
            for (auto& sub : subs) {
1520
313
                if (!sub.has_value()) {
1521
313
                    node.has_duplicate_keys = true;
1522
313
                    return {};
1523
313
                }
1524
313
            }
1525
1526
            // Start building the set of keys involved in this node and children.
1527
            // Start by keys in this node directly.
1528
313
            size_t keys_count = node.keys.size();
1529
313
            keyset key_set{node.keys.begin(), node.keys.end(), Comp(ctx)};
1530
313
            if (key_set.size() != keys_count) {
1531
                // It already has duplicates; bail out.
1532
313
                node.has_duplicate_keys = true;
1533
313
                return {};
1534
313
            }
1535
1536
            // Merge the keys from the children into this set.
1537
313
            for (auto& sub : subs) {
1538
313
                keys_count += sub->size();
1539
                // Small optimization: std::set::merge is linear in the size of the second arg but
1540
                // logarithmic in the size of the first.
1541
313
                if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1542
313
                key_set.merge(*sub);
1543
313
                if (key_set.size() != keys_count) {
1544
313
                    node.has_duplicate_keys = true;
1545
313
                    return {};
1546
313
                }
1547
313
            }
1548
1549
313
            node.has_duplicate_keys = false;
1550
313
            return key_set;
1551
313
        };
1552
1553
313
        TreeEval<state>(upfn);
1554
313
    }
descriptor.cpp:void miniscript::Node<unsigned int>::DuplicateKeyCheck<(anonymous namespace)::KeyParser>((anonymous namespace)::KeyParser const&) const
Line
Count
Source
1499
791
    {
1500
        // We cannot use a lambda here, as lambdas are non assignable, and the set operations
1501
        // below require moving the comparators around.
1502
791
        struct Comp {
1503
791
            const Ctx* ctx_ptr;
1504
791
            Comp(const Ctx& ctx) : ctx_ptr(&ctx) {}
1505
791
            bool operator()(const Key& a, const Key& b) const { return ctx_ptr->KeyCompare(a, b); }
1506
791
        };
1507
1508
        // state in the recursive computation:
1509
        // - std::nullopt means "this node has duplicates"
1510
        // - an std::set means "this node has no duplicate keys, and they are: ...".
1511
791
        using keyset = std::set<Key, Comp>;
1512
791
        using state = std::optional<keyset>;
1513
1514
791
        auto upfn = [&ctx](const Node& node, std::span<state> subs) -> state {
1515
            // If this node is already known to have duplicates, nothing left to do.
1516
791
            if (node.has_duplicate_keys.has_value() && *node.has_duplicate_keys) return {};
1517
1518
            // Check if one of the children is already known to have duplicates.
1519
791
            for (auto& sub : subs) {
1520
791
                if (!sub.has_value()) {
1521
791
                    node.has_duplicate_keys = true;
1522
791
                    return {};
1523
791
                }
1524
791
            }
1525
1526
            // Start building the set of keys involved in this node and children.
1527
            // Start by keys in this node directly.
1528
791
            size_t keys_count = node.keys.size();
1529
791
            keyset key_set{node.keys.begin(), node.keys.end(), Comp(ctx)};
1530
791
            if (key_set.size() != keys_count) {
1531
                // It already has duplicates; bail out.
1532
791
                node.has_duplicate_keys = true;
1533
791
                return {};
1534
791
            }
1535
1536
            // Merge the keys from the children into this set.
1537
791
            for (auto& sub : subs) {
1538
791
                keys_count += sub->size();
1539
                // Small optimization: std::set::merge is linear in the size of the second arg but
1540
                // logarithmic in the size of the first.
1541
791
                if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1542
791
                key_set.merge(*sub);
1543
791
                if (key_set.size() != keys_count) {
1544
791
                    node.has_duplicate_keys = true;
1545
791
                    return {};
1546
791
                }
1547
791
            }
1548
1549
791
            node.has_duplicate_keys = false;
1550
791
            return key_set;
1551
791
        };
1552
1553
791
        TreeEval<state>(upfn);
1554
791
    }
void miniscript::Node<XOnlyPubKey>::DuplicateKeyCheck<TapSatisfier>(TapSatisfier const&) const
Line
Count
Source
1499
3.05k
    {
1500
        // We cannot use a lambda here, as lambdas are non assignable, and the set operations
1501
        // below require moving the comparators around.
1502
3.05k
        struct Comp {
1503
3.05k
            const Ctx* ctx_ptr;
1504
3.05k
            Comp(const Ctx& ctx) : ctx_ptr(&ctx) {}
1505
3.05k
            bool operator()(const Key& a, const Key& b) const { return ctx_ptr->KeyCompare(a, b); }
1506
3.05k
        };
1507
1508
        // state in the recursive computation:
1509
        // - std::nullopt means "this node has duplicates"
1510
        // - an std::set means "this node has no duplicate keys, and they are: ...".
1511
3.05k
        using keyset = std::set<Key, Comp>;
1512
3.05k
        using state = std::optional<keyset>;
1513
1514
3.05k
        auto upfn = [&ctx](const Node& node, std::span<state> subs) -> state {
1515
            // If this node is already known to have duplicates, nothing left to do.
1516
3.05k
            if (node.has_duplicate_keys.has_value() && *node.has_duplicate_keys) return {};
1517
1518
            // Check if one of the children is already known to have duplicates.
1519
3.05k
            for (auto& sub : subs) {
1520
3.05k
                if (!sub.has_value()) {
1521
3.05k
                    node.has_duplicate_keys = true;
1522
3.05k
                    return {};
1523
3.05k
                }
1524
3.05k
            }
1525
1526
            // Start building the set of keys involved in this node and children.
1527
            // Start by keys in this node directly.
1528
3.05k
            size_t keys_count = node.keys.size();
1529
3.05k
            keyset key_set{node.keys.begin(), node.keys.end(), Comp(ctx)};
1530
3.05k
            if (key_set.size() != keys_count) {
1531
                // It already has duplicates; bail out.
1532
3.05k
                node.has_duplicate_keys = true;
1533
3.05k
                return {};
1534
3.05k
            }
1535
1536
            // Merge the keys from the children into this set.
1537
3.05k
            for (auto& sub : subs) {
1538
3.05k
                keys_count += sub->size();
1539
                // Small optimization: std::set::merge is linear in the size of the second arg but
1540
                // logarithmic in the size of the first.
1541
3.05k
                if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1542
3.05k
                key_set.merge(*sub);
1543
3.05k
                if (key_set.size() != keys_count) {
1544
3.05k
                    node.has_duplicate_keys = true;
1545
3.05k
                    return {};
1546
3.05k
                }
1547
3.05k
            }
1548
1549
3.05k
            node.has_duplicate_keys = false;
1550
3.05k
            return key_set;
1551
3.05k
        };
1552
1553
3.05k
        TreeEval<state>(upfn);
1554
3.05k
    }
void miniscript::Node<CPubKey>::DuplicateKeyCheck<WshSatisfier>(WshSatisfier const&) const
Line
Count
Source
1499
213
    {
1500
        // We cannot use a lambda here, as lambdas are non assignable, and the set operations
1501
        // below require moving the comparators around.
1502
213
        struct Comp {
1503
213
            const Ctx* ctx_ptr;
1504
213
            Comp(const Ctx& ctx) : ctx_ptr(&ctx) {}
1505
213
            bool operator()(const Key& a, const Key& b) const { return ctx_ptr->KeyCompare(a, b); }
1506
213
        };
1507
1508
        // state in the recursive computation:
1509
        // - std::nullopt means "this node has duplicates"
1510
        // - an std::set means "this node has no duplicate keys, and they are: ...".
1511
213
        using keyset = std::set<Key, Comp>;
1512
213
        using state = std::optional<keyset>;
1513
1514
213
        auto upfn = [&ctx](const Node& node, std::span<state> subs) -> state {
1515
            // If this node is already known to have duplicates, nothing left to do.
1516
213
            if (node.has_duplicate_keys.has_value() && *node.has_duplicate_keys) return {};
1517
1518
            // Check if one of the children is already known to have duplicates.
1519
213
            for (auto& sub : subs) {
1520
213
                if (!sub.has_value()) {
1521
213
                    node.has_duplicate_keys = true;
1522
213
                    return {};
1523
213
                }
1524
213
            }
1525
1526
            // Start building the set of keys involved in this node and children.
1527
            // Start by keys in this node directly.
1528
213
            size_t keys_count = node.keys.size();
1529
213
            keyset key_set{node.keys.begin(), node.keys.end(), Comp(ctx)};
1530
213
            if (key_set.size() != keys_count) {
1531
                // It already has duplicates; bail out.
1532
213
                node.has_duplicate_keys = true;
1533
213
                return {};
1534
213
            }
1535
1536
            // Merge the keys from the children into this set.
1537
213
            for (auto& sub : subs) {
1538
213
                keys_count += sub->size();
1539
                // Small optimization: std::set::merge is linear in the size of the second arg but
1540
                // logarithmic in the size of the first.
1541
213
                if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1542
213
                key_set.merge(*sub);
1543
213
                if (key_set.size() != keys_count) {
1544
213
                    node.has_duplicate_keys = true;
1545
213
                    return {};
1546
213
                }
1547
213
            }
1548
1549
213
            node.has_duplicate_keys = false;
1550
213
            return key_set;
1551
213
        };
1552
1553
213
        TreeEval<state>(upfn);
1554
213
    }
1555
1556
    //! Return the size of the script for this expression (faster than ToScript().size()).
1557
13.0M
    size_t ScriptSize() const { return scriptlen; }
miniscript::Node<CPubKey>::ScriptSize() const
Line
Count
Source
1557
57.0k
    size_t ScriptSize() const { return scriptlen; }
miniscript::Node<unsigned int>::ScriptSize() const
Line
Count
Source
1557
2.39M
    size_t ScriptSize() const { return scriptlen; }
miniscript::Node<XOnlyPubKey>::ScriptSize() const
Line
Count
Source
1557
10.5M
    size_t ScriptSize() const { return scriptlen; }
1558
1559
    //! Return the maximum number of ops needed to satisfy this script non-malleably.
1560
2.17k
    std::optional<uint32_t> GetOps() const {
1561
2.17k
        if (!ops.sat.Valid()) return {};
1562
2.16k
        return ops.count + ops.sat.Value();
1563
2.17k
    }
miniscript::Node<CPubKey>::GetOps() const
Line
Count
Source
1560
1.63k
    std::optional<uint32_t> GetOps() const {
1561
1.63k
        if (!ops.sat.Valid()) return {};
1562
1.62k
        return ops.count + ops.sat.Value();
1563
1.63k
    }
miniscript::Node<unsigned int>::GetOps() const
Line
Count
Source
1560
548
    std::optional<uint32_t> GetOps() const {
1561
548
        if (!ops.sat.Valid()) return {};
1562
545
        return ops.count + ops.sat.Value();
1563
548
    }
1564
1565
    //! Return the number of ops in the script (not counting the dynamic ones that depend on execution).
1566
    uint32_t GetStaticOps() const { return ops.count; }
1567
1568
    //! Check the ops limit of this script against the consensus limit.
1569
6.36k
    bool CheckOpsLimit() const {
1570
6.36k
        if (IsTapscript(m_script_ctx)) return true;
1571
2.05k
        if (const auto ops = GetOps()) return *ops <= MAX_OPS_PER_SCRIPT;
1572
12
        return true;
1573
2.05k
    }
miniscript::Node<CPubKey>::CheckOpsLimit() const
Line
Count
Source
1569
5.48k
    bool CheckOpsLimit() const {
1570
5.48k
        if (IsTapscript(m_script_ctx)) return true;
1571
1.50k
        if (const auto ops = GetOps()) return *ops <= MAX_OPS_PER_SCRIPT;
1572
9
        return true;
1573
1.50k
    }
miniscript::Node<unsigned int>::CheckOpsLimit() const
Line
Count
Source
1569
886
    bool CheckOpsLimit() const {
1570
886
        if (IsTapscript(m_script_ctx)) return true;
1571
548
        if (const auto ops = GetOps()) return *ops <= MAX_OPS_PER_SCRIPT;
1572
3
        return true;
1573
548
    }
1574
1575
    /** Whether this node is of type B, K or W. (That is, anything but V.) */
1576
7.16k
    bool IsBKW() const {
1577
7.16k
        return !((GetType() & "BKW"_mst) == ""_mst);
1578
7.16k
    }
miniscript::Node<CPubKey>::IsBKW() const
Line
Count
Source
1576
5.97k
    bool IsBKW() const {
1577
5.97k
        return !((GetType() & "BKW"_mst) == ""_mst);
1578
5.97k
    }
miniscript::Node<unsigned int>::IsBKW() const
Line
Count
Source
1576
1.18k
    bool IsBKW() const {
1577
1.18k
        return !((GetType() & "BKW"_mst) == ""_mst);
1578
1.18k
    }
1579
1580
    /** Return the maximum number of stack elements needed to satisfy this script non-malleably. */
1581
2.75k
    std::optional<uint32_t> GetStackSize() const {
1582
2.75k
        if (!ss.Sat().Valid()) return {};
1583
2.73k
        return ss.Sat().NetDiff() + static_cast<int32_t>(IsBKW());
1584
2.75k
    }
miniscript::Node<CPubKey>::GetStackSize() const
Line
Count
Source
1581
1.89k
    std::optional<uint32_t> GetStackSize() const {
1582
1.89k
        if (!ss.Sat().Valid()) return {};
1583
1.88k
        return ss.Sat().NetDiff() + static_cast<int32_t>(IsBKW());
1584
1.89k
    }
miniscript::Node<unsigned int>::GetStackSize() const
Line
Count
Source
1581
853
    std::optional<uint32_t> GetStackSize() const {
1582
853
        if (!ss.Sat().Valid()) return {};
1583
849
        return ss.Sat().NetDiff() + static_cast<int32_t>(IsBKW());
1584
853
    }
1585
1586
    //! Return the maximum size of the stack during execution of this script.
1587
4.43k
    std::optional<uint32_t> GetExecStackSize() const {
1588
4.43k
        if (!ss.Sat().Valid()) return {};
1589
4.42k
        return ss.Sat().Exec() + static_cast<int32_t>(IsBKW());
1590
4.43k
    }
miniscript::Node<CPubKey>::GetExecStackSize() const
Line
Count
Source
1587
4.09k
    std::optional<uint32_t> GetExecStackSize() const {
1588
4.09k
        if (!ss.Sat().Valid()) return {};
1589
4.08k
        return ss.Sat().Exec() + static_cast<int32_t>(IsBKW());
1590
4.09k
    }
miniscript::Node<unsigned int>::GetExecStackSize() const
Line
Count
Source
1587
338
    std::optional<uint32_t> GetExecStackSize() const {
1588
338
        if (!ss.Sat().Valid()) return {};
1589
338
        return ss.Sat().Exec() + static_cast<int32_t>(IsBKW());
1590
338
    }
1591
1592
    //! Check the maximum stack size for this script against the policy limit.
1593
6.36k
    bool CheckStackSize() const {
1594
        // Since in Tapscript there is no standardness limit on the script and witness sizes, we may run
1595
        // into the maximum stack size while executing the script. Make sure it doesn't happen.
1596
6.36k
        if (IsTapscript(m_script_ctx)) {
1597
4.31k
            if (const auto exec_ss = GetExecStackSize()) return exec_ss <= MAX_STACK_SIZE;
1598
9
            return true;
1599
4.31k
        }
1600
2.05k
        if (const auto ss = GetStackSize()) return *ss <= MAX_STANDARD_P2WSH_STACK_ITEMS;
1601
12
        return true;
1602
2.05k
    }
miniscript::Node<CPubKey>::CheckStackSize() const
Line
Count
Source
1593
5.48k
    bool CheckStackSize() const {
1594
        // Since in Tapscript there is no standardness limit on the script and witness sizes, we may run
1595
        // into the maximum stack size while executing the script. Make sure it doesn't happen.
1596
5.48k
        if (IsTapscript(m_script_ctx)) {
1597
3.97k
            if (const auto exec_ss = GetExecStackSize()) return exec_ss <= MAX_STACK_SIZE;
1598
9
            return true;
1599
3.97k
        }
1600
1.50k
        if (const auto ss = GetStackSize()) return *ss <= MAX_STANDARD_P2WSH_STACK_ITEMS;
1601
9
        return true;
1602
1.50k
    }
miniscript::Node<unsigned int>::CheckStackSize() const
Line
Count
Source
1593
886
    bool CheckStackSize() const {
1594
        // Since in Tapscript there is no standardness limit on the script and witness sizes, we may run
1595
        // into the maximum stack size while executing the script. Make sure it doesn't happen.
1596
886
        if (IsTapscript(m_script_ctx)) {
1597
338
            if (const auto exec_ss = GetExecStackSize()) return exec_ss <= MAX_STACK_SIZE;
1598
0
            return true;
1599
338
        }
1600
548
        if (const auto ss = GetStackSize()) return *ss <= MAX_STANDARD_P2WSH_STACK_ITEMS;
1601
3
        return true;
1602
548
    }
1603
1604
    //! Whether no satisfaction exists for this node.
1605
163
    bool IsNotSatisfiable() const { return !GetStackSize(); }
1606
1607
    /** Return the maximum size in bytes of a witness to satisfy this script non-malleably. Note this does
1608
     * not include the witness script push. */
1609
531
    std::optional<uint32_t> GetWitnessSize() const {
1610
531
        if (!ws.sat.Valid()) return {};
1611
531
        return ws.sat.Value();
1612
531
    }
miniscript::Node<CPubKey>::GetWitnessSize() const
Line
Count
Source
1609
373
    std::optional<uint32_t> GetWitnessSize() const {
1610
373
        if (!ws.sat.Valid()) return {};
1611
373
        return ws.sat.Value();
1612
373
    }
miniscript::Node<unsigned int>::GetWitnessSize() const
Line
Count
Source
1609
158
    std::optional<uint32_t> GetWitnessSize() const {
1610
158
        if (!ws.sat.Valid()) return {};
1611
158
        return ws.sat.Value();
1612
158
    }
1613
1614
    //! Return the expression type.
1615
123M
    Type GetType() const { return typ; }
miniscript::Node<CPubKey>::GetType() const
Line
Count
Source
1615
24.3M
    Type GetType() const { return typ; }
miniscript::Node<unsigned int>::GetType() const
Line
Count
Source
1615
4.13M
    Type GetType() const { return typ; }
miniscript::Node<XOnlyPubKey>::GetType() const
Line
Count
Source
1615
95.0M
    Type GetType() const { return typ; }
1616
1617
    //! Return the script context for this node.
1618
1.47k
    MiniscriptContext GetMsCtx() const { return m_script_ctx; }
1619
1620
    //! Find an insane subnode which has no insane children. Nullptr if there is none.
1621
15
    const Node* FindInsaneSub() const {
1622
114
        return TreeEval<const Node*>([](const Node& node, std::span<const Node*> subs) -> const Node* {
1623
114
            for (auto& sub: subs) if (sub) return sub;
1624
103
            if (!node.IsSaneSubexpression()) return &node;
1625
92
            return nullptr;
1626
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
1622
7
        return TreeEval<const Node*>([](const Node& node, std::span<const Node*> subs) -> const Node* {
1623
7
            for (auto& sub: subs) if (sub) return sub;
1624
6
            if (!node.IsSaneSubexpression()) return &node;
1625
5
            return nullptr;
1626
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
1622
107
        return TreeEval<const Node*>([](const Node& node, std::span<const Node*> subs) -> const Node* {
1623
107
            for (auto& sub: subs) if (sub) return sub;
1624
97
            if (!node.IsSaneSubexpression()) return &node;
1625
87
            return nullptr;
1626
97
        });
1627
15
    }
miniscript::Node<CPubKey>::FindInsaneSub() const
Line
Count
Source
1621
1
    const Node* FindInsaneSub() const {
1622
1
        return TreeEval<const Node*>([](const Node& node, std::span<const Node*> subs) -> const Node* {
1623
1
            for (auto& sub: subs) if (sub) return sub;
1624
1
            if (!node.IsSaneSubexpression()) return &node;
1625
1
            return nullptr;
1626
1
        });
1627
1
    }
miniscript::Node<unsigned int>::FindInsaneSub() const
Line
Count
Source
1621
14
    const Node* FindInsaneSub() const {
1622
14
        return TreeEval<const Node*>([](const Node& node, std::span<const Node*> subs) -> const Node* {
1623
14
            for (auto& sub: subs) if (sub) return sub;
1624
14
            if (!node.IsSaneSubexpression()) return &node;
1625
14
            return nullptr;
1626
14
        });
1627
14
    }
1628
1629
    //! Determine whether a Miniscript node is satisfiable. fn(node) will be invoked for all
1630
    //! key, time, and hashing nodes, and should return their satisfiability.
1631
    template<typename F>
1632
    bool IsSatisfiable(F fn) const
1633
375
    {
1634
        // TreeEval() doesn't support bool as NodeType, so use int instead.
1635
25.4k
        return TreeEval<int>([&fn](const Node& node, std::span<int> subs) -> bool {
1636
25.4k
            switch (node.fragment) {
1637
249
                case Fragment::JUST_0:
1638
249
                    return false;
1639
231
                case Fragment::JUST_1:
1640
231
                    return true;
1641
1.36k
                case Fragment::PK_K:
1642
1.44k
                case Fragment::PK_H:
1643
1.47k
                case Fragment::MULTI:
1644
1.48k
                case Fragment::MULTI_A:
1645
1.67k
                case Fragment::AFTER:
1646
7.79k
                case Fragment::OLDER:
1647
7.83k
                case Fragment::HASH256:
1648
7.85k
                case Fragment::HASH160:
1649
7.91k
                case Fragment::SHA256:
1650
7.93k
                case Fragment::RIPEMD160:
1651
7.93k
                    return bool{fn(node)};
1652
87
                case Fragment::ANDOR:
1653
87
                    return (subs[0] && subs[1]) || subs[2];
1654
198
                case Fragment::AND_V:
1655
7.45k
                case Fragment::AND_B:
1656
7.45k
                    return subs[0] && subs[1];
1657
24
                case Fragment::OR_B:
1658
42
                case Fragment::OR_C:
1659
87
                case Fragment::OR_D:
1660
324
                case Fragment::OR_I:
1661
324
                    return subs[0] || subs[1];
1662
48
                case Fragment::THRESH:
1663
48
                    return static_cast<uint32_t>(std::count(subs.begin(), subs.end(), true)) >= node.k;
1664
9.08k
                default: // wrappers
1665
9.08k
                    assert(subs.size() >= 1);
1666
9.08k
                    CHECK_NONFATAL(subs.size() == 1);
1667
9.08k
                    return subs[0];
1668
25.4k
            }
1669
25.4k
        });
1670
375
    }
1671
1672
    //! Check whether this node is valid at all.
1673
5.98M
    bool IsValid() const {
1674
5.98M
        if (GetType() == ""_mst) return false;
1675
5.98M
        return ScriptSize() <= internal::MaxScriptSize(m_script_ctx);
1676
5.98M
    }
miniscript::Node<CPubKey>::IsValid() const
Line
Count
Source
1673
30.8k
    bool IsValid() const {
1674
30.8k
        if (GetType() == ""_mst) return false;
1675
30.7k
        return ScriptSize() <= internal::MaxScriptSize(m_script_ctx);
1676
30.8k
    }
miniscript::Node<unsigned int>::IsValid() const
Line
Count
Source
1673
673k
    bool IsValid() const {
1674
673k
        if (GetType() == ""_mst) return false;
1675
673k
        return ScriptSize() <= internal::MaxScriptSize(m_script_ctx);
1676
673k
    }
miniscript::Node<XOnlyPubKey>::IsValid() const
Line
Count
Source
1673
5.28M
    bool IsValid() const {
1674
5.28M
        if (GetType() == ""_mst) return false;
1675
5.28M
        return ScriptSize() <= internal::MaxScriptSize(m_script_ctx);
1676
5.28M
    }
1677
1678
    //! Check whether this node is valid as a script on its own.
1679
10.1k
    bool IsValidTopLevel() const { return IsValid() && GetType() << "B"_mst; }
miniscript::Node<CPubKey>::IsValidTopLevel() const
Line
Count
Source
1679
5.66k
    bool IsValidTopLevel() const { return IsValid() && GetType() << "B"_mst; }
miniscript::Node<unsigned int>::IsValidTopLevel() const
Line
Count
Source
1679
1.40k
    bool IsValidTopLevel() const { return IsValid() && GetType() << "B"_mst; }
miniscript::Node<XOnlyPubKey>::IsValidTopLevel() const
Line
Count
Source
1679
3.05k
    bool IsValidTopLevel() const { return IsValid() && GetType() << "B"_mst; }
1680
1681
    //! Check whether this script can always be satisfied in a non-malleable way.
1682
6.21k
    bool IsNonMalleable() const { return GetType() << "m"_mst; }
miniscript::Node<CPubKey>::IsNonMalleable() const
Line
Count
Source
1682
5.31k
    bool IsNonMalleable() const { return GetType() << "m"_mst; }
miniscript::Node<unsigned int>::IsNonMalleable() const
Line
Count
Source
1682
895
    bool IsNonMalleable() const { return GetType() << "m"_mst; }
1683
1684
    //! Check whether this script always needs a signature.
1685
4.77k
    bool NeedsSignature() const { return GetType() << "s"_mst; }
miniscript::Node<CPubKey>::NeedsSignature() const
Line
Count
Source
1685
3.98k
    bool NeedsSignature() const { return GetType() << "s"_mst; }
miniscript::Node<unsigned int>::NeedsSignature() const
Line
Count
Source
1685
786
    bool NeedsSignature() const { return GetType() << "s"_mst; }
1686
1687
    //! Check whether there is no satisfaction path that contains both timelocks and heightlocks
1688
5.03k
    bool CheckTimeLocksMix() const { return GetType() << "k"_mst; }
miniscript::Node<CPubKey>::CheckTimeLocksMix() const
Line
Count
Source
1688
4.15k
    bool CheckTimeLocksMix() const { return GetType() << "k"_mst; }
miniscript::Node<unsigned int>::CheckTimeLocksMix() const
Line
Count
Source
1688
884
    bool CheckTimeLocksMix() const { return GetType() << "k"_mst; }
1689
1690
    //! Check whether there is no duplicate key across this fragment and all its sub-fragments.
1691
4.77k
    bool CheckDuplicateKey() const { return has_duplicate_keys && !*has_duplicate_keys; }
miniscript::Node<CPubKey>::CheckDuplicateKey() const
Line
Count
Source
1691
3.89k
    bool CheckDuplicateKey() const { return has_duplicate_keys && !*has_duplicate_keys; }
miniscript::Node<unsigned int>::CheckDuplicateKey() const
Line
Count
Source
1691
876
    bool CheckDuplicateKey() const { return has_duplicate_keys && !*has_duplicate_keys; }
1692
1693
    //! Whether successful non-malleable satisfactions are guaranteed to be valid.
1694
6.36k
    bool ValidSatisfactions() const { return IsValid() && CheckOpsLimit() && CheckStackSize(); }
miniscript::Node<CPubKey>::ValidSatisfactions() const
Line
Count
Source
1694
5.47k
    bool ValidSatisfactions() const { return IsValid() && CheckOpsLimit() && CheckStackSize(); }
miniscript::Node<unsigned int>::ValidSatisfactions() const
Line
Count
Source
1694
890
    bool ValidSatisfactions() const { return IsValid() && CheckOpsLimit() && CheckStackSize(); }
1695
1696
    //! Whether the apparent policy of this node matches its script semantics. Doesn't guarantee it is a safe script on its own.
1697
6.10k
    bool IsSaneSubexpression() const { return ValidSatisfactions() && IsNonMalleable() && CheckTimeLocksMix() && CheckDuplicateKey(); }
miniscript::Node<CPubKey>::IsSaneSubexpression() const
Line
Count
Source
1697
5.21k
    bool IsSaneSubexpression() const { return ValidSatisfactions() && IsNonMalleable() && CheckTimeLocksMix() && CheckDuplicateKey(); }
miniscript::Node<unsigned int>::IsSaneSubexpression() const
Line
Count
Source
1697
890
    bool IsSaneSubexpression() const { return ValidSatisfactions() && IsNonMalleable() && CheckTimeLocksMix() && CheckDuplicateKey(); }
1698
1699
    //! Check whether this node is safe as a script on its own.
1700
6.00k
    bool IsSane() const { return IsValidTopLevel() && IsSaneSubexpression() && NeedsSignature(); }
miniscript::Node<CPubKey>::IsSane() const
Line
Count
Source
1700
5.20k
    bool IsSane() const { return IsValidTopLevel() && IsSaneSubexpression() && NeedsSignature(); }
miniscript::Node<unsigned int>::IsSane() const
Line
Count
Source
1700
797
    bool IsSane() const { return IsValidTopLevel() && IsSaneSubexpression() && NeedsSignature(); }
1701
1702
    //! Produce a witness for this script, if possible and given the information available in the context.
1703
    //! The non-malleable satisfaction is guaranteed to be valid if it exists, and ValidSatisfaction()
1704
    //! is true. If IsSane() holds, this satisfaction is guaranteed to succeed in case the node's
1705
    //! conditions are satisfied (private keys and hash preimages available, locktimes satisfied).
1706
    template<typename Ctx>
1707
8.09k
    Availability Satisfy(const Ctx& ctx, std::vector<std::vector<unsigned char>>& stack, bool nonmalleable = true) const {
1708
8.09k
        auto ret = ProduceInput(ctx);
1709
8.09k
        if (nonmalleable && (ret.sat.malleable || !ret.sat.has_sig)) return Availability::NO;
1710
3.38k
        stack = std::move(ret.sat.stack);
1711
3.38k
        return ret.sat.available;
1712
8.09k
    }
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
1707
4.82k
    Availability Satisfy(const Ctx& ctx, std::vector<std::vector<unsigned char>>& stack, bool nonmalleable = true) const {
1708
4.82k
        auto ret = ProduceInput(ctx);
1709
4.82k
        if (nonmalleable && (ret.sat.malleable || !ret.sat.has_sig)) return Availability::NO;
1710
2.67k
        stack = std::move(ret.sat.stack);
1711
2.67k
        return ret.sat.available;
1712
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
1707
3.05k
    Availability Satisfy(const Ctx& ctx, std::vector<std::vector<unsigned char>>& stack, bool nonmalleable = true) const {
1708
3.05k
        auto ret = ProduceInput(ctx);
1709
3.05k
        if (nonmalleable && (ret.sat.malleable || !ret.sat.has_sig)) return Availability::NO;
1710
621
        stack = std::move(ret.sat.stack);
1711
621
        return ret.sat.available;
1712
3.05k
    }
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
1707
213
    Availability Satisfy(const Ctx& ctx, std::vector<std::vector<unsigned char>>& stack, bool nonmalleable = true) const {
1708
213
        auto ret = ProduceInput(ctx);
1709
213
        if (nonmalleable && (ret.sat.malleable || !ret.sat.has_sig)) return Availability::NO;
1710
84
        stack = std::move(ret.sat.stack);
1711
84
        return ret.sat.available;
1712
213
    }
1713
1714
    //! Equality testing.
1715
    bool operator==(const Node<Key>& arg) const { return Compare(*this, arg) == 0; }
1716
1717
    // Constructors with various argument combinations, which bypass the duplicate key check.
1718
    Node(internal::NoDupCheck, MiniscriptContext script_ctx, enum Fragment nt, std::vector<Node> sub, std::vector<unsigned char> arg, uint32_t val = 0)
1719
        : 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()) {}
1720
    Node(internal::NoDupCheck, MiniscriptContext script_ctx, enum Fragment nt, std::vector<unsigned char> arg, uint32_t val = 0)
1721
358
        : 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
1721
151
        : 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
1721
195
        : 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
1721
12
        : fragment(nt), k(val), data(std::move(arg)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1722
    Node(internal::NoDupCheck, MiniscriptContext script_ctx, enum Fragment nt, std::vector<Node> sub, std::vector<Key> key, uint32_t val = 0)
1723
        : 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()) {}
1724
    Node(internal::NoDupCheck, MiniscriptContext script_ctx, enum Fragment nt, std::vector<Key> key, uint32_t val = 0)
1725
6.72k
        : 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
1725
1.82k
        : 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
1725
1.73k
        : 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
1725
3.17k
        : fragment(nt), k(val), keys(std::move(key)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1726
    Node(internal::NoDupCheck, MiniscriptContext script_ctx, enum Fragment nt, std::vector<Node> sub, uint32_t val = 0)
1727
6.48M
        : 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
1727
17.6k
        : 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
1727
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
1727
5.27M
        : fragment(nt), k(val), subs(std::move(sub)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1728
    Node(internal::NoDupCheck, MiniscriptContext script_ctx, enum Fragment nt, uint32_t val = 0)
1729
9.84k
        : 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
1729
8.63k
        : fragment(nt), k(val), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
miniscript::Node<unsigned int>::Node(miniscript::internal::NoDupCheck, miniscript::MiniscriptContext, miniscript::Fragment, unsigned int)
Line
Count
Source
1729
775
        : 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
1729
429
        : fragment(nt), k(val), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1730
1731
    // Constructors with various argument combinations, which do perform the duplicate key check.
1732
    template <typename Ctx> Node(const Ctx& ctx, enum Fragment nt, std::vector<Node> sub, std::vector<unsigned char> arg, uint32_t val = 0)
1733
        : Node(internal::NoDupCheck{}, ctx.MsContext(), nt, std::move(sub), std::move(arg), val) { DuplicateKeyCheck(ctx); }
1734
    template <typename Ctx> Node(const Ctx& ctx, enum Fragment nt, std::vector<unsigned char> arg, uint32_t val = 0)
1735
        : Node(internal::NoDupCheck{}, ctx.MsContext(), nt, std::move(arg), val) { DuplicateKeyCheck(ctx);}
1736
    template <typename Ctx> Node(const Ctx& ctx, enum Fragment nt, std::vector<Node> sub, std::vector<Key> key, uint32_t val = 0)
1737
        : Node(internal::NoDupCheck{}, ctx.MsContext(), nt, std::move(sub), std::move(key), val) { DuplicateKeyCheck(ctx); }
1738
    template <typename Ctx> Node(const Ctx& ctx, enum Fragment nt, std::vector<Key> key, uint32_t val = 0)
1739
        : Node(internal::NoDupCheck{}, ctx.MsContext(), nt, std::move(key), val) { DuplicateKeyCheck(ctx); }
1740
    template <typename Ctx> Node(const Ctx& ctx, enum Fragment nt, std::vector<Node> sub, uint32_t val = 0)
1741
        : Node(internal::NoDupCheck{}, ctx.MsContext(), nt, std::move(sub), val) { DuplicateKeyCheck(ctx); }
1742
    template <typename Ctx> Node(const Ctx& ctx, enum Fragment nt, uint32_t val = 0)
1743
        : Node(internal::NoDupCheck{}, ctx.MsContext(), nt, val) { DuplicateKeyCheck(ctx); }
1744
1745
    // Delete copy constructor and assignment operator, use Clone() instead
1746
    Node(const Node&) = delete;
1747
    Node& operator=(const Node&) = delete;
1748
1749
    // subs is movable, circumventing recursion, so these are permitted.
1750
8.12M
    Node(Node&&) noexcept = default;
miniscript::Node<CPubKey>::Node(miniscript::Node<CPubKey>&&)
Line
Count
Source
1750
44.8k
    Node(Node&&) noexcept = default;
miniscript::Node<unsigned int>::Node(miniscript::Node<unsigned int>&&)
Line
Count
Source
1750
2.79M
    Node(Node&&) noexcept = default;
miniscript::Node<XOnlyPubKey>::Node(miniscript::Node<XOnlyPubKey>&&)
Line
Count
Source
1750
5.28M
    Node(Node&&) noexcept = default;
1751
6.48M
    Node& operator=(Node&&) noexcept = default;
miniscript::Node<unsigned int>::operator=(miniscript::Node<unsigned int>&&)
Line
Count
Source
1751
1.19M
    Node& operator=(Node&&) noexcept = default;
miniscript::Node<CPubKey>::operator=(miniscript::Node<CPubKey>&&)
Line
Count
Source
1751
16.8k
    Node& operator=(Node&&) noexcept = default;
miniscript::Node<XOnlyPubKey>::operator=(miniscript::Node<XOnlyPubKey>&&)
Line
Count
Source
1751
5.27M
    Node& operator=(Node&&) noexcept = default;
1752
};
1753
1754
namespace internal {
1755
1756
enum class ParseContext {
1757
    /** An expression which may be begin with wrappers followed by a colon. */
1758
    WRAPPED_EXPR,
1759
    /** A miniscript expression which does not begin with wrappers. */
1760
    EXPR,
1761
1762
    /** SWAP wraps the top constructed node with s: */
1763
    SWAP,
1764
    /** ALT wraps the top constructed node with a: */
1765
    ALT,
1766
    /** CHECK wraps the top constructed node with c: */
1767
    CHECK,
1768
    /** DUP_IF wraps the top constructed node with d: */
1769
    DUP_IF,
1770
    /** VERIFY wraps the top constructed node with v: */
1771
    VERIFY,
1772
    /** NON_ZERO wraps the top constructed node with j: */
1773
    NON_ZERO,
1774
    /** ZERO_NOTEQUAL wraps the top constructed node with n: */
1775
    ZERO_NOTEQUAL,
1776
    /** WRAP_U will construct an or_i(X,0) node from the top constructed node. */
1777
    WRAP_U,
1778
    /** WRAP_T will construct an and_v(X,1) node from the top constructed node. */
1779
    WRAP_T,
1780
1781
    /** AND_N will construct an andor(X,Y,0) node from the last two constructed nodes. */
1782
    AND_N,
1783
    /** AND_V will construct an and_v node from the last two constructed nodes. */
1784
    AND_V,
1785
    /** AND_B will construct an and_b node from the last two constructed nodes. */
1786
    AND_B,
1787
    /** ANDOR will construct an andor node from the last three constructed nodes. */
1788
    ANDOR,
1789
    /** OR_B will construct an or_b node from the last two constructed nodes. */
1790
    OR_B,
1791
    /** OR_C will construct an or_c node from the last two constructed nodes. */
1792
    OR_C,
1793
    /** OR_D will construct an or_d node from the last two constructed nodes. */
1794
    OR_D,
1795
    /** OR_I will construct an or_i node from the last two constructed nodes. */
1796
    OR_I,
1797
1798
    /** THRESH will read a wrapped expression, and then look for a COMMA. If
1799
     * no comma follows, it will construct a thresh node from the appropriate
1800
     * number of constructed children. Otherwise, it will recurse with another
1801
     * THRESH. */
1802
    THRESH,
1803
1804
    /** COMMA expects the next element to be ',' and fails if not. */
1805
    COMMA,
1806
    /** CLOSE_BRACKET expects the next element to be ')' and fails if not. */
1807
    CLOSE_BRACKET,
1808
};
1809
1810
int FindNextChar(std::span<const char> in, char m);
1811
1812
/** Parse a key expression fully contained within a fragment with the name given by 'func' */
1813
template<typename Key, typename Ctx>
1814
std::optional<Key> ParseKey(const std::string& func, std::span<const char>& in, const Ctx& ctx)
1815
1.15k
{
1816
1.15k
    std::span<const char> expr = script::Expr(in);
1817
1.15k
    if (!script::Func(func, expr)) return {};
1818
1.15k
    return ctx.FromString(expr);
1819
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
1815
794
{
1816
794
    std::span<const char> expr = script::Expr(in);
1817
794
    if (!script::Func(func, expr)) return {};
1818
794
    return ctx.FromString(expr);
1819
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
1815
361
{
1816
361
    std::span<const char> expr = script::Expr(in);
1817
361
    if (!script::Func(func, expr)) return {};
1818
359
    return ctx.FromString(expr);
1819
361
}
1820
1821
/** Parse a hex string fully contained within a fragment with the name given by 'func' */
1822
template<typename Ctx>
1823
std::optional<std::vector<unsigned char>> ParseHexStr(const std::string& func, std::span<const char>& in, const size_t expected_size,
1824
                                                                         const Ctx& ctx)
1825
89
{
1826
89
    std::span<const char> expr = script::Expr(in);
1827
89
    if (!script::Func(func, expr)) return {};
1828
89
    std::string val = std::string(expr.begin(), expr.end());
1829
89
    if (!IsHex(val)) return {};
1830
89
    auto hash = ParseHex(val);
1831
89
    if (hash.size() != expected_size) return {};
1832
89
    return hash;
1833
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
1825
49
{
1826
49
    std::span<const char> expr = script::Expr(in);
1827
49
    if (!script::Func(func, expr)) return {};
1828
49
    std::string val = std::string(expr.begin(), expr.end());
1829
49
    if (!IsHex(val)) return {};
1830
49
    auto hash = ParseHex(val);
1831
49
    if (hash.size() != expected_size) return {};
1832
49
    return hash;
1833
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
1825
40
{
1826
40
    std::span<const char> expr = script::Expr(in);
1827
40
    if (!script::Func(func, expr)) return {};
1828
40
    std::string val = std::string(expr.begin(), expr.end());
1829
40
    if (!IsHex(val)) return {};
1830
40
    auto hash = ParseHex(val);
1831
40
    if (hash.size() != expected_size) return {};
1832
40
    return hash;
1833
40
}
1834
1835
/** BuildBack pops the last two elements off `constructed` and wraps them in the specified Fragment */
1836
template<typename Key>
1837
void BuildBack(const MiniscriptContext script_ctx, Fragment nt, std::vector<Node<Key>>& constructed, const bool reverse = false)
1838
9.22k
{
1839
9.22k
    Node<Key> child{std::move(constructed.back())};
1840
9.22k
    constructed.pop_back();
1841
9.22k
    if (reverse) {
1842
4.36k
        constructed.back() = Node<Key>{internal::NoDupCheck{}, script_ctx, nt, Vector(std::move(child), std::move(constructed.back()))};
1843
4.85k
    } else {
1844
4.85k
        constructed.back() = Node<Key>{internal::NoDupCheck{}, script_ctx, nt, Vector(std::move(constructed.back()), std::move(child))};
1845
4.85k
    }
1846
9.22k
}
void miniscript::internal::BuildBack<CPubKey>(miniscript::MiniscriptContext, miniscript::Fragment, std::vector<miniscript::Node<CPubKey>, std::allocator<miniscript::Node<CPubKey>>>&, bool)
Line
Count
Source
1838
7.53k
{
1839
7.53k
    Node<Key> child{std::move(constructed.back())};
1840
7.53k
    constructed.pop_back();
1841
7.53k
    if (reverse) {
1842
2.93k
        constructed.back() = Node<Key>{internal::NoDupCheck{}, script_ctx, nt, Vector(std::move(child), std::move(constructed.back()))};
1843
4.59k
    } else {
1844
4.59k
        constructed.back() = Node<Key>{internal::NoDupCheck{}, script_ctx, nt, Vector(std::move(constructed.back()), std::move(child))};
1845
4.59k
    }
1846
7.53k
}
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
1838
1.16k
{
1839
1.16k
    Node<Key> child{std::move(constructed.back())};
1840
1.16k
    constructed.pop_back();
1841
1.16k
    if (reverse) {
1842
906
        constructed.back() = Node<Key>{internal::NoDupCheck{}, script_ctx, nt, Vector(std::move(child), std::move(constructed.back()))};
1843
906
    } else {
1844
258
        constructed.back() = Node<Key>{internal::NoDupCheck{}, script_ctx, nt, Vector(std::move(constructed.back()), std::move(child))};
1845
258
    }
1846
1.16k
}
void miniscript::internal::BuildBack<XOnlyPubKey>(miniscript::MiniscriptContext, miniscript::Fragment, std::vector<miniscript::Node<XOnlyPubKey>, std::allocator<miniscript::Node<XOnlyPubKey>>>&, bool)
Line
Count
Source
1838
521
{
1839
521
    Node<Key> child{std::move(constructed.back())};
1840
521
    constructed.pop_back();
1841
521
    if (reverse) {
1842
521
        constructed.back() = Node<Key>{internal::NoDupCheck{}, script_ctx, nt, Vector(std::move(child), std::move(constructed.back()))};
1843
521
    } else {
1844
0
        constructed.back() = Node<Key>{internal::NoDupCheck{}, script_ctx, nt, Vector(std::move(constructed.back()), std::move(child))};
1845
0
    }
1846
521
}
1847
1848
/**
1849
 * Parse a miniscript from its textual descriptor form.
1850
 * This does not check whether the script is valid, let alone sane. The caller is expected to use
1851
 * the `IsValidTopLevel()` and `IsSaneTopLevel()` to check for these properties on the node.
1852
 */
1853
template <typename Key, typename Ctx>
1854
inline std::optional<Node<Key>> Parse(std::span<const char> in, const Ctx& ctx)
1855
753
{
1856
753
    using namespace script;
1857
1858
    // Account for the minimum script size for all parsed fragments so far. It "borrows" 1
1859
    // script byte from all leaf nodes, counting it instead whenever a space for a recursive
1860
    // expression is added (through andor, and_*, or_*, thresh). This guarantees that all fragments
1861
    // increment the script_size by at least one, except for:
1862
    // - "0", "1": these leafs are only a single byte, so their subtracted-from increment is 0.
1863
    //   This is not an issue however, as "space" for them has to be created by combinators,
1864
    //   which do increment script_size.
1865
    // - "v:": the v wrapper adds nothing as in some cases it results in no opcode being added
1866
    //   (instead transforming another opcode into its VERIFY form). However, the v: wrapper has
1867
    //   to be interleaved with other fragments to be valid, so this is not a concern.
1868
753
    size_t script_size{1};
1869
753
    size_t max_size{internal::MaxScriptSize(ctx.MsContext())};
1870
1871
    // The two integers are used to hold state for thresh()
1872
753
    std::vector<std::tuple<ParseContext, int64_t, int64_t>> to_parse;
1873
753
    std::vector<Node<Key>> constructed;
1874
1875
753
    to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
1876
1877
    // Parses a multi() or multi_a() from its string representation. Returns false on parsing error.
1878
753
    const auto parse_multi_exp = [&](std::span<const char>& in, const bool is_multi_a) -> bool {
1879
59
        const auto max_keys{is_multi_a ? MAX_PUBKEYS_PER_MULTI_A : MAX_PUBKEYS_PER_MULTISIG};
1880
59
        const auto required_ctx{is_multi_a ? MiniscriptContext::TAPSCRIPT : MiniscriptContext::P2WSH};
1881
59
        if (ctx.MsContext() != required_ctx) return false;
1882
        // Get threshold
1883
47
        int next_comma = FindNextChar(in, ',');
1884
47
        if (next_comma < 1) return false;
1885
47
        const auto k_to_integral{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
1886
47
        if (!k_to_integral.has_value()) return false;
1887
46
        const int64_t k{k_to_integral.value()};
1888
46
        in = in.subspan(next_comma + 1);
1889
        // Get keys. It is compatible for both compressed and x-only keys.
1890
46
        std::vector<Key> keys;
1891
175
        while (next_comma != -1) {
1892
129
            next_comma = FindNextChar(in, ',');
1893
129
            int key_length = (next_comma == -1) ? FindNextChar(in, ')') : next_comma;
1894
129
            if (key_length < 1) return false;
1895
129
            std::span<const char> sp{in.begin(), in.begin() + key_length};
1896
129
            auto key = ctx.FromString(sp);
1897
129
            if (!key) return false;
1898
129
            keys.push_back(std::move(*key));
1899
129
            in = in.subspan(key_length + 1);
1900
129
        }
1901
46
        if (keys.size() < 1 || keys.size() > max_keys) return false;
1902
46
        if (k < 1 || k > (int64_t)keys.size()) return false;
1903
46
        if (is_multi_a) {
1904
            // (push + xonly-key + CHECKSIG[ADD]) * n + k + OP_NUMEQUAL(VERIFY), minus one.
1905
16
            script_size += (1 + 32 + 1) * keys.size() + BuildScript(k).size();
1906
16
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), k);
1907
30
        } else {
1908
30
            script_size += 2 + (keys.size() > 16) + (k > 16) + 34 * keys.size();
1909
30
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), k);
1910
30
        }
1911
46
        return true;
1912
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
1878
27
    const auto parse_multi_exp = [&](std::span<const char>& in, const bool is_multi_a) -> bool {
1879
27
        const auto max_keys{is_multi_a ? MAX_PUBKEYS_PER_MULTI_A : MAX_PUBKEYS_PER_MULTISIG};
1880
27
        const auto required_ctx{is_multi_a ? MiniscriptContext::TAPSCRIPT : MiniscriptContext::P2WSH};
1881
27
        if (ctx.MsContext() != required_ctx) return false;
1882
        // Get threshold
1883
16
        int next_comma = FindNextChar(in, ',');
1884
16
        if (next_comma < 1) return false;
1885
16
        const auto k_to_integral{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
1886
16
        if (!k_to_integral.has_value()) return false;
1887
15
        const int64_t k{k_to_integral.value()};
1888
15
        in = in.subspan(next_comma + 1);
1889
        // Get keys. It is compatible for both compressed and x-only keys.
1890
15
        std::vector<Key> keys;
1891
64
        while (next_comma != -1) {
1892
49
            next_comma = FindNextChar(in, ',');
1893
49
            int key_length = (next_comma == -1) ? FindNextChar(in, ')') : next_comma;
1894
49
            if (key_length < 1) return false;
1895
49
            std::span<const char> sp{in.begin(), in.begin() + key_length};
1896
49
            auto key = ctx.FromString(sp);
1897
49
            if (!key) return false;
1898
49
            keys.push_back(std::move(*key));
1899
49
            in = in.subspan(key_length + 1);
1900
49
        }
1901
15
        if (keys.size() < 1 || keys.size() > max_keys) return false;
1902
15
        if (k < 1 || k > (int64_t)keys.size()) return false;
1903
15
        if (is_multi_a) {
1904
            // (push + xonly-key + CHECKSIG[ADD]) * n + k + OP_NUMEQUAL(VERIFY), minus one.
1905
2
            script_size += (1 + 32 + 1) * keys.size() + BuildScript(k).size();
1906
2
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), k);
1907
13
        } else {
1908
13
            script_size += 2 + (keys.size() > 16) + (k > 16) + 34 * keys.size();
1909
13
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), k);
1910
13
        }
1911
15
        return true;
1912
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
1878
32
    const auto parse_multi_exp = [&](std::span<const char>& in, const bool is_multi_a) -> bool {
1879
32
        const auto max_keys{is_multi_a ? MAX_PUBKEYS_PER_MULTI_A : MAX_PUBKEYS_PER_MULTISIG};
1880
32
        const auto required_ctx{is_multi_a ? MiniscriptContext::TAPSCRIPT : MiniscriptContext::P2WSH};
1881
32
        if (ctx.MsContext() != required_ctx) return false;
1882
        // Get threshold
1883
31
        int next_comma = FindNextChar(in, ',');
1884
31
        if (next_comma < 1) return false;
1885
31
        const auto k_to_integral{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
1886
31
        if (!k_to_integral.has_value()) return false;
1887
31
        const int64_t k{k_to_integral.value()};
1888
31
        in = in.subspan(next_comma + 1);
1889
        // Get keys. It is compatible for both compressed and x-only keys.
1890
31
        std::vector<Key> keys;
1891
111
        while (next_comma != -1) {
1892
80
            next_comma = FindNextChar(in, ',');
1893
80
            int key_length = (next_comma == -1) ? FindNextChar(in, ')') : next_comma;
1894
80
            if (key_length < 1) return false;
1895
80
            std::span<const char> sp{in.begin(), in.begin() + key_length};
1896
80
            auto key = ctx.FromString(sp);
1897
80
            if (!key) return false;
1898
80
            keys.push_back(std::move(*key));
1899
80
            in = in.subspan(key_length + 1);
1900
80
        }
1901
31
        if (keys.size() < 1 || keys.size() > max_keys) return false;
1902
31
        if (k < 1 || k > (int64_t)keys.size()) return false;
1903
31
        if (is_multi_a) {
1904
            // (push + xonly-key + CHECKSIG[ADD]) * n + k + OP_NUMEQUAL(VERIFY), minus one.
1905
14
            script_size += (1 + 32 + 1) * keys.size() + BuildScript(k).size();
1906
14
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), k);
1907
17
        } else {
1908
17
            script_size += 2 + (keys.size() > 16) + (k > 16) + 34 * keys.size();
1909
17
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), k);
1910
17
        }
1911
31
        return true;
1912
31
    };
1913
1914
379k
    while (!to_parse.empty()) {
1915
379k
        if (script_size > max_size) return {};
1916
1917
        // Get the current context we are decoding within
1918
379k
        auto [cur_context, n, k] = to_parse.back();
1919
379k
        to_parse.pop_back();
1920
1921
379k
        switch (cur_context) {
1922
14.1k
        case ParseContext::WRAPPED_EXPR: {
1923
14.1k
            std::optional<size_t> colon_index{};
1924
698k
            for (size_t i = 1; i < in.size(); ++i) {
1925
698k
                if (in[i] == ':') {
1926
6.73k
                    colon_index = i;
1927
6.73k
                    break;
1928
6.73k
                }
1929
691k
                if (in[i] < 'a' || in[i] > 'z') break;
1930
691k
            }
1931
            // If there is no colon, this loop won't execute
1932
14.1k
            bool last_was_v{false};
1933
679k
            for (size_t j = 0; colon_index && j < *colon_index; ++j) {
1934
665k
                if (script_size > max_size) return {};
1935
665k
                if (in[j] == 'a') {
1936
6.28k
                    script_size += 2;
1937
6.28k
                    to_parse.emplace_back(ParseContext::ALT, -1, -1);
1938
659k
                } else if (in[j] == 's') {
1939
72
                    script_size += 1;
1940
72
                    to_parse.emplace_back(ParseContext::SWAP, -1, -1);
1941
659k
                } else if (in[j] == 'c') {
1942
72
                    script_size += 1;
1943
72
                    to_parse.emplace_back(ParseContext::CHECK, -1, -1);
1944
659k
                } else if (in[j] == 'd') {
1945
18
                    script_size += 3;
1946
18
                    to_parse.emplace_back(ParseContext::DUP_IF, -1, -1);
1947
659k
                } else if (in[j] == 'j') {
1948
10
                    script_size += 4;
1949
10
                    to_parse.emplace_back(ParseContext::NON_ZERO, -1, -1);
1950
659k
                } else if (in[j] == 'n') {
1951
658k
                    script_size += 1;
1952
658k
                    to_parse.emplace_back(ParseContext::ZERO_NOTEQUAL, -1, -1);
1953
658k
                } else if (in[j] == 'v') {
1954
                    // do not permit "...vv...:"; it's not valid, and also doesn't trigger early
1955
                    // failure as script_size isn't incremented.
1956
261
                    if (last_was_v) return {};
1957
261
                    to_parse.emplace_back(ParseContext::VERIFY, -1, -1);
1958
261
                } else if (in[j] == 'u') {
1959
23
                    script_size += 4;
1960
23
                    to_parse.emplace_back(ParseContext::WRAP_U, -1, -1);
1961
105
                } else if (in[j] == 't') {
1962
46
                    script_size += 1;
1963
46
                    to_parse.emplace_back(ParseContext::WRAP_T, -1, -1);
1964
59
                } else if (in[j] == 'l') {
1965
                    // The l: wrapper is equivalent to or_i(0,X)
1966
59
                    script_size += 4;
1967
59
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
1968
59
                    to_parse.emplace_back(ParseContext::OR_I, -1, -1);
1969
59
                } else {
1970
0
                    return {};
1971
0
                }
1972
665k
                last_was_v = (in[j] == 'v');
1973
665k
            }
1974
14.1k
            to_parse.emplace_back(ParseContext::EXPR, -1, -1);
1975
14.1k
            if (colon_index) in = in.subspan(*colon_index + 1);
1976
14.1k
            break;
1977
14.1k
        }
1978
14.1k
        case ParseContext::EXPR: {
1979
14.1k
            if (Const("0", in)) {
1980
59
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
1981
14.1k
            } else if (Const("1", in)) {
1982
115
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1);
1983
14.0k
            } else if (Const("pk(", in, /*skip=*/false)) {
1984
966
                std::optional<Key> key = ParseKey<Key, Ctx>("pk", in, ctx);
1985
966
                if (!key) return {};
1986
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)))));
1987
964
                script_size += IsTapscript(ctx.MsContext()) ? 33 : 34;
1988
13.0k
            } else if (Const("pkh(", in, /*skip=*/false)) {
1989
85
                std::optional<Key> key = ParseKey<Key, Ctx>("pkh", in, ctx);
1990
85
                if (!key) return {};
1991
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)))));
1992
85
                script_size += 24;
1993
12.9k
            } else if (Const("pk_k(", in, /*skip=*/false)) {
1994
76
                std::optional<Key> key = ParseKey<Key, Ctx>("pk_k", in, ctx);
1995
76
                if (!key) return {};
1996
74
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_K, Vector(std::move(*key)));
1997
74
                script_size += IsTapscript(ctx.MsContext()) ? 32 : 33;
1998
12.8k
            } else if (Const("pk_h(", in, /*skip=*/false)) {
1999
28
                std::optional<Key> key = ParseKey<Key, Ctx>("pk_h", in, ctx);
2000
28
                if (!key) return {};
2001
28
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_H, Vector(std::move(*key)));
2002
28
                script_size += 23;
2003
12.8k
            } else if (Const("sha256(", in, /*skip=*/false)) {
2004
30
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("sha256", in, 32, ctx);
2005
30
                if (!hash) return {};
2006
30
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, std::move(*hash));
2007
30
                script_size += 38;
2008
12.8k
            } else if (Const("ripemd160(", in, /*skip=*/false)) {
2009
15
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("ripemd160", in, 20, ctx);
2010
15
                if (!hash) return {};
2011
15
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::RIPEMD160, std::move(*hash));
2012
15
                script_size += 26;
2013
12.8k
            } else if (Const("hash256(", in, /*skip=*/false)) {
2014
22
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("hash256", in, 32, ctx);
2015
22
                if (!hash) return {};
2016
22
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, std::move(*hash));
2017
22
                script_size += 38;
2018
12.7k
            } else if (Const("hash160(", in, /*skip=*/false)) {
2019
22
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("hash160", in, 20, ctx);
2020
22
                if (!hash) return {};
2021
22
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, std::move(*hash));
2022
22
                script_size += 26;
2023
12.7k
            } else if (Const("after(", in, /*skip=*/false)) {
2024
128
                auto expr = Expr(in);
2025
128
                if (!Func("after", expr)) return {};
2026
128
                const auto num{ToIntegral<int64_t>(std::string_view(expr.begin(), expr.end()))};
2027
128
                if (!num.has_value() || *num < 1 || *num >= 0x80000000L) return {};
2028
122
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num);
2029
122
                script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
2030
12.6k
            } else if (Const("older(", in, /*skip=*/false)) {
2031
5.55k
                auto expr = Expr(in);
2032
5.55k
                if (!Func("older", expr)) return {};
2033
5.55k
                const auto num{ToIntegral<int64_t>(std::string_view(expr.begin(), expr.end()))};
2034
5.55k
                if (!num.has_value() || *num < 1 || *num >= 0x80000000L) return {};
2035
5.55k
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num);
2036
5.55k
                script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
2037
7.07k
            } else if (Const("multi(", in)) {
2038
41
                if (!parse_multi_exp(in, /* is_multi_a = */false)) return {};
2039
7.03k
            } else if (Const("multi_a(", in)) {
2040
18
                if (!parse_multi_exp(in, /* is_multi_a = */true)) return {};
2041
7.01k
            } else if (Const("thresh(", in)) {
2042
58
                int next_comma = FindNextChar(in, ',');
2043
58
                if (next_comma < 1) return {};
2044
58
                const auto k{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
2045
58
                if (!k.has_value() || *k < 1) return {};
2046
55
                in = in.subspan(next_comma + 1);
2047
                // n = 1 here because we read the first WRAPPED_EXPR before reaching THRESH
2048
55
                to_parse.emplace_back(ParseContext::THRESH, 1, *k);
2049
55
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2050
55
                script_size += 2 + (*k > 16) + (*k > 0x7f) + (*k > 0x7fff) + (*k > 0x7fffff);
2051
6.95k
            } else if (Const("andor(", in)) {
2052
55
                to_parse.emplace_back(ParseContext::ANDOR, -1, -1);
2053
55
                to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
2054
55
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2055
55
                to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2056
55
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2057
55
                to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2058
55
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2059
55
                script_size += 5;
2060
6.90k
            } else {
2061
6.90k
                if (Const("and_n(", in)) {
2062
16
                    to_parse.emplace_back(ParseContext::AND_N, -1, -1);
2063
16
                    script_size += 5;
2064
6.88k
                } else if (Const("and_b(", in)) {
2065
6.19k
                    to_parse.emplace_back(ParseContext::AND_B, -1, -1);
2066
6.19k
                    script_size += 2;
2067
6.19k
                } else if (Const("and_v(", in)) {
2068
185
                    to_parse.emplace_back(ParseContext::AND_V, -1, -1);
2069
185
                    script_size += 1;
2070
505
                } else if (Const("or_b(", in)) {
2071
45
                    to_parse.emplace_back(ParseContext::OR_B, -1, -1);
2072
45
                    script_size += 2;
2073
460
                } else if (Const("or_c(", in)) {
2074
28
                    to_parse.emplace_back(ParseContext::OR_C, -1, -1);
2075
28
                    script_size += 3;
2076
432
                } else if (Const("or_d(", in)) {
2077
42
                    to_parse.emplace_back(ParseContext::OR_D, -1, -1);
2078
42
                    script_size += 4;
2079
390
                } else if (Const("or_i(", in)) {
2080
45
                    to_parse.emplace_back(ParseContext::OR_I, -1, -1);
2081
45
                    script_size += 4;
2082
345
                } else {
2083
345
                    return {};
2084
345
                }
2085
6.55k
                to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
2086
6.55k
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2087
6.55k
                to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2088
6.55k
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2089
6.55k
            }
2090
13.7k
            break;
2091
14.1k
        }
2092
13.7k
        case ParseContext::ALT: {
2093
4.56k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A, Vector(std::move(constructed.back()))};
2094
4.56k
            break;
2095
14.1k
        }
2096
72
        case ParseContext::SWAP: {
2097
72
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S, Vector(std::move(constructed.back()))};
2098
72
            break;
2099
14.1k
        }
2100
68
        case ParseContext::CHECK: {
2101
68
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(std::move(constructed.back()))};
2102
68
            break;
2103
14.1k
        }
2104
18
        case ParseContext::DUP_IF: {
2105
18
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D, Vector(std::move(constructed.back()))};
2106
18
            break;
2107
14.1k
        }
2108
8
        case ParseContext::NON_ZERO: {
2109
8
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J, Vector(std::move(constructed.back()))};
2110
8
            break;
2111
14.1k
        }
2112
329k
        case ParseContext::ZERO_NOTEQUAL: {
2113
329k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N, Vector(std::move(constructed.back()))};
2114
329k
            break;
2115
14.1k
        }
2116
255
        case ParseContext::VERIFY: {
2117
255
            script_size += (constructed.back().GetType() << "x"_mst);
2118
255
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V, Vector(std::move(constructed.back()))};
2119
255
            break;
2120
14.1k
        }
2121
16
        case ParseContext::WRAP_U: {
2122
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})};
2123
16
            break;
2124
14.1k
        }
2125
45
        case ParseContext::WRAP_T: {
2126
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})};
2127
45
            break;
2128
14.1k
        }
2129
4.46k
        case ParseContext::AND_B: {
2130
4.46k
            BuildBack(ctx.MsContext(), Fragment::AND_B, constructed);
2131
4.46k
            break;
2132
14.1k
        }
2133
16
        case ParseContext::AND_N: {
2134
16
            auto mid = std::move(constructed.back());
2135
16
            constructed.pop_back();
2136
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})};
2137
16
            break;
2138
14.1k
        }
2139
176
        case ParseContext::AND_V: {
2140
176
            BuildBack(ctx.MsContext(), Fragment::AND_V, constructed);
2141
176
            break;
2142
14.1k
        }
2143
44
        case ParseContext::OR_B: {
2144
44
            BuildBack(ctx.MsContext(), Fragment::OR_B, constructed);
2145
44
            break;
2146
14.1k
        }
2147
26
        case ParseContext::OR_C: {
2148
26
            BuildBack(ctx.MsContext(), Fragment::OR_C, constructed);
2149
26
            break;
2150
14.1k
        }
2151
41
        case ParseContext::OR_D: {
2152
41
            BuildBack(ctx.MsContext(), Fragment::OR_D, constructed);
2153
41
            break;
2154
14.1k
        }
2155
99
        case ParseContext::OR_I: {
2156
99
            BuildBack(ctx.MsContext(), Fragment::OR_I, constructed);
2157
99
            break;
2158
14.1k
        }
2159
52
        case ParseContext::ANDOR: {
2160
52
            auto right = std::move(constructed.back());
2161
52
            constructed.pop_back();
2162
52
            auto mid = std::move(constructed.back());
2163
52
            constructed.pop_back();
2164
52
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR, Vector(std::move(constructed.back()), std::move(mid), std::move(right))};
2165
52
            break;
2166
14.1k
        }
2167
164
        case ParseContext::THRESH: {
2168
164
            if (in.size() < 1) return {};
2169
164
            if (in[0] == ',') {
2170
110
                in = in.subspan(1);
2171
110
                to_parse.emplace_back(ParseContext::THRESH, n+1, k);
2172
110
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2173
110
                script_size += 2;
2174
110
            } else if (in[0] == ')') {
2175
54
                if (k > n) return {};
2176
52
                in = in.subspan(1);
2177
                // Children are constructed in reverse order, so iterate from end to beginning
2178
52
                std::vector<Node<Key>> subs;
2179
212
                for (int i = 0; i < n; ++i) {
2180
160
                    subs.push_back(std::move(constructed.back()));
2181
160
                    constructed.pop_back();
2182
160
                }
2183
52
                std::reverse(subs.begin(), subs.end());
2184
52
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs), k);
2185
52
            } else {
2186
0
                return {};
2187
0
            }
2188
162
            break;
2189
164
        }
2190
6.64k
        case ParseContext::COMMA: {
2191
6.64k
            if (in.size() < 1 || in[0] != ',') return {};
2192
6.64k
            in = in.subspan(1);
2193
6.64k
            break;
2194
6.64k
        }
2195
4.86k
        case ParseContext::CLOSE_BRACKET: {
2196
4.86k
            if (in.size() < 1 || in[0] != ')') return {};
2197
4.86k
            in = in.subspan(1);
2198
4.86k
            break;
2199
4.86k
        }
2200
379k
        }
2201
379k
    }
2202
2203
    // Sanity checks on the produced miniscript
2204
753
    assert(constructed.size() >= 1);
2205
370
    CHECK_NONFATAL(constructed.size() == 1);
2206
370
    assert(constructed[0].ScriptSize() == script_size);
2207
370
    if (in.size() > 0) return {};
2208
367
    Node<Key> tl_node{std::move(constructed.front())};
2209
367
    tl_node.DuplicateKeyCheck(ctx);
2210
367
    return tl_node;
2211
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
1855
220
{
1856
220
    using namespace script;
1857
1858
    // Account for the minimum script size for all parsed fragments so far. It "borrows" 1
1859
    // script byte from all leaf nodes, counting it instead whenever a space for a recursive
1860
    // expression is added (through andor, and_*, or_*, thresh). This guarantees that all fragments
1861
    // increment the script_size by at least one, except for:
1862
    // - "0", "1": these leafs are only a single byte, so their subtracted-from increment is 0.
1863
    //   This is not an issue however, as "space" for them has to be created by combinators,
1864
    //   which do increment script_size.
1865
    // - "v:": the v wrapper adds nothing as in some cases it results in no opcode being added
1866
    //   (instead transforming another opcode into its VERIFY form). However, the v: wrapper has
1867
    //   to be interleaved with other fragments to be valid, so this is not a concern.
1868
220
    size_t script_size{1};
1869
220
    size_t max_size{internal::MaxScriptSize(ctx.MsContext())};
1870
1871
    // The two integers are used to hold state for thresh()
1872
220
    std::vector<std::tuple<ParseContext, int64_t, int64_t>> to_parse;
1873
220
    std::vector<Node<Key>> constructed;
1874
1875
220
    to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
1876
1877
    // Parses a multi() or multi_a() from its string representation. Returns false on parsing error.
1878
220
    const auto parse_multi_exp = [&](std::span<const char>& in, const bool is_multi_a) -> bool {
1879
220
        const auto max_keys{is_multi_a ? MAX_PUBKEYS_PER_MULTI_A : MAX_PUBKEYS_PER_MULTISIG};
1880
220
        const auto required_ctx{is_multi_a ? MiniscriptContext::TAPSCRIPT : MiniscriptContext::P2WSH};
1881
220
        if (ctx.MsContext() != required_ctx) return false;
1882
        // Get threshold
1883
220
        int next_comma = FindNextChar(in, ',');
1884
220
        if (next_comma < 1) return false;
1885
220
        const auto k_to_integral{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
1886
220
        if (!k_to_integral.has_value()) return false;
1887
220
        const int64_t k{k_to_integral.value()};
1888
220
        in = in.subspan(next_comma + 1);
1889
        // Get keys. It is compatible for both compressed and x-only keys.
1890
220
        std::vector<Key> keys;
1891
220
        while (next_comma != -1) {
1892
220
            next_comma = FindNextChar(in, ',');
1893
220
            int key_length = (next_comma == -1) ? FindNextChar(in, ')') : next_comma;
1894
220
            if (key_length < 1) return false;
1895
220
            std::span<const char> sp{in.begin(), in.begin() + key_length};
1896
220
            auto key = ctx.FromString(sp);
1897
220
            if (!key) return false;
1898
220
            keys.push_back(std::move(*key));
1899
220
            in = in.subspan(key_length + 1);
1900
220
        }
1901
220
        if (keys.size() < 1 || keys.size() > max_keys) return false;
1902
220
        if (k < 1 || k > (int64_t)keys.size()) return false;
1903
220
        if (is_multi_a) {
1904
            // (push + xonly-key + CHECKSIG[ADD]) * n + k + OP_NUMEQUAL(VERIFY), minus one.
1905
220
            script_size += (1 + 32 + 1) * keys.size() + BuildScript(k).size();
1906
220
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), k);
1907
220
        } else {
1908
220
            script_size += 2 + (keys.size() > 16) + (k > 16) + 34 * keys.size();
1909
220
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), k);
1910
220
        }
1911
220
        return true;
1912
220
    };
1913
1914
46.4k
    while (!to_parse.empty()) {
1915
46.2k
        if (script_size > max_size) return {};
1916
1917
        // Get the current context we are decoding within
1918
46.2k
        auto [cur_context, n, k] = to_parse.back();
1919
46.2k
        to_parse.pop_back();
1920
1921
46.2k
        switch (cur_context) {
1922
12.9k
        case ParseContext::WRAPPED_EXPR: {
1923
12.9k
            std::optional<size_t> colon_index{};
1924
36.2k
            for (size_t i = 1; i < in.size(); ++i) {
1925
36.2k
                if (in[i] == ':') {
1926
6.42k
                    colon_index = i;
1927
6.42k
                    break;
1928
6.42k
                }
1929
29.8k
                if (in[i] < 'a' || in[i] > 'z') break;
1930
29.8k
            }
1931
            // If there is no colon, this loop won't execute
1932
12.9k
            bool last_was_v{false};
1933
19.4k
            for (size_t j = 0; colon_index && j < *colon_index; ++j) {
1934
6.52k
                if (script_size > max_size) return {};
1935
6.52k
                if (in[j] == 'a') {
1936
6.20k
                    script_size += 2;
1937
6.20k
                    to_parse.emplace_back(ParseContext::ALT, -1, -1);
1938
6.20k
                } else if (in[j] == 's') {
1939
21
                    script_size += 1;
1940
21
                    to_parse.emplace_back(ParseContext::SWAP, -1, -1);
1941
303
                } else if (in[j] == 'c') {
1942
56
                    script_size += 1;
1943
56
                    to_parse.emplace_back(ParseContext::CHECK, -1, -1);
1944
247
                } else if (in[j] == 'd') {
1945
8
                    script_size += 3;
1946
8
                    to_parse.emplace_back(ParseContext::DUP_IF, -1, -1);
1947
239
                } else if (in[j] == 'j') {
1948
10
                    script_size += 4;
1949
10
                    to_parse.emplace_back(ParseContext::NON_ZERO, -1, -1);
1950
229
                } else if (in[j] == 'n') {
1951
16
                    script_size += 1;
1952
16
                    to_parse.emplace_back(ParseContext::ZERO_NOTEQUAL, -1, -1);
1953
213
                } else if (in[j] == 'v') {
1954
                    // do not permit "...vv...:"; it's not valid, and also doesn't trigger early
1955
                    // failure as script_size isn't incremented.
1956
103
                    if (last_was_v) return {};
1957
103
                    to_parse.emplace_back(ParseContext::VERIFY, -1, -1);
1958
110
                } else if (in[j] == 'u') {
1959
23
                    script_size += 4;
1960
23
                    to_parse.emplace_back(ParseContext::WRAP_U, -1, -1);
1961
87
                } else if (in[j] == 't') {
1962
44
                    script_size += 1;
1963
44
                    to_parse.emplace_back(ParseContext::WRAP_T, -1, -1);
1964
44
                } else if (in[j] == 'l') {
1965
                    // The l: wrapper is equivalent to or_i(0,X)
1966
43
                    script_size += 4;
1967
43
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
1968
43
                    to_parse.emplace_back(ParseContext::OR_I, -1, -1);
1969
43
                } else {
1970
0
                    return {};
1971
0
                }
1972
6.52k
                last_was_v = (in[j] == 'v');
1973
6.52k
            }
1974
12.9k
            to_parse.emplace_back(ParseContext::EXPR, -1, -1);
1975
12.9k
            if (colon_index) in = in.subspan(*colon_index + 1);
1976
12.9k
            break;
1977
12.9k
        }
1978
12.9k
        case ParseContext::EXPR: {
1979
12.9k
            if (Const("0", in)) {
1980
56
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
1981
12.9k
            } else if (Const("1", in)) {
1982
112
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1);
1983
12.7k
            } else if (Const("pk(", in, /*skip=*/false)) {
1984
715
                std::optional<Key> key = ParseKey<Key, Ctx>("pk", in, ctx);
1985
715
                if (!key) return {};
1986
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)))));
1987
715
                script_size += IsTapscript(ctx.MsContext()) ? 33 : 34;
1988
12.0k
            } else if (Const("pkh(", in, /*skip=*/false)) {
1989
3
                std::optional<Key> key = ParseKey<Key, Ctx>("pkh", in, ctx);
1990
3
                if (!key) return {};
1991
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)))));
1992
3
                script_size += 24;
1993
12.0k
            } else if (Const("pk_k(", in, /*skip=*/false)) {
1994
51
                std::optional<Key> key = ParseKey<Key, Ctx>("pk_k", in, ctx);
1995
51
                if (!key) return {};
1996
51
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_K, Vector(std::move(*key)));
1997
51
                script_size += IsTapscript(ctx.MsContext()) ? 32 : 33;
1998
12.0k
            } else if (Const("pk_h(", in, /*skip=*/false)) {
1999
25
                std::optional<Key> key = ParseKey<Key, Ctx>("pk_h", in, ctx);
2000
25
                if (!key) return {};
2001
25
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_H, Vector(std::move(*key)));
2002
25
                script_size += 23;
2003
11.9k
            } else if (Const("sha256(", in, /*skip=*/false)) {
2004
22
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("sha256", in, 32, ctx);
2005
22
                if (!hash) return {};
2006
22
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, std::move(*hash));
2007
22
                script_size += 38;
2008
11.9k
            } else if (Const("ripemd160(", in, /*skip=*/false)) {
2009
7
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("ripemd160", in, 20, ctx);
2010
7
                if (!hash) return {};
2011
7
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::RIPEMD160, std::move(*hash));
2012
7
                script_size += 26;
2013
11.9k
            } else if (Const("hash256(", in, /*skip=*/false)) {
2014
14
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("hash256", in, 32, ctx);
2015
14
                if (!hash) return {};
2016
14
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, std::move(*hash));
2017
14
                script_size += 38;
2018
11.9k
            } else if (Const("hash160(", in, /*skip=*/false)) {
2019
6
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("hash160", in, 20, ctx);
2020
6
                if (!hash) return {};
2021
6
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, std::move(*hash));
2022
6
                script_size += 26;
2023
11.9k
            } else if (Const("after(", in, /*skip=*/false)) {
2024
79
                auto expr = Expr(in);
2025
79
                if (!Func("after", expr)) return {};
2026
79
                const auto num{ToIntegral<int64_t>(std::string_view(expr.begin(), expr.end()))};
2027
79
                if (!num.has_value() || *num < 1 || *num >= 0x80000000L) return {};
2028
73
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num);
2029
73
                script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
2030
11.8k
            } else if (Const("older(", in, /*skip=*/false)) {
2031
5.48k
                auto expr = Expr(in);
2032
5.48k
                if (!Func("older", expr)) return {};
2033
5.48k
                const auto num{ToIntegral<int64_t>(std::string_view(expr.begin(), expr.end()))};
2034
5.48k
                if (!num.has_value() || *num < 1 || *num >= 0x80000000L) return {};
2035
5.47k
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num);
2036
5.47k
                script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
2037
6.38k
            } else if (Const("multi(", in)) {
2038
23
                if (!parse_multi_exp(in, /* is_multi_a = */false)) return {};
2039
6.36k
            } else if (Const("multi_a(", in)) {
2040
4
                if (!parse_multi_exp(in, /* is_multi_a = */true)) return {};
2041
6.35k
            } else if (Const("thresh(", in)) {
2042
25
                int next_comma = FindNextChar(in, ',');
2043
25
                if (next_comma < 1) return {};
2044
25
                const auto k{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
2045
25
                if (!k.has_value() || *k < 1) return {};
2046
22
                in = in.subspan(next_comma + 1);
2047
                // n = 1 here because we read the first WRAPPED_EXPR before reaching THRESH
2048
22
                to_parse.emplace_back(ParseContext::THRESH, 1, *k);
2049
22
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2050
22
                script_size += 2 + (*k > 16) + (*k > 0x7f) + (*k > 0x7fff) + (*k > 0x7fffff);
2051
6.33k
            } else if (Const("andor(", in)) {
2052
30
                to_parse.emplace_back(ParseContext::ANDOR, -1, -1);
2053
30
                to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
2054
30
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2055
30
                to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2056
30
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2057
30
                to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2058
30
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2059
30
                script_size += 5;
2060
6.30k
            } else {
2061
6.30k
                if (Const("and_n(", in)) {
2062
8
                    to_parse.emplace_back(ParseContext::AND_N, -1, -1);
2063
8
                    script_size += 5;
2064
6.29k
                } else if (Const("and_b(", in)) {
2065
6.15k
                    to_parse.emplace_back(ParseContext::AND_B, -1, -1);
2066
6.15k
                    script_size += 2;
2067
6.15k
                } else if (Const("and_v(", in)) {
2068
43
                    to_parse.emplace_back(ParseContext::AND_V, -1, -1);
2069
43
                    script_size += 1;
2070
97
                } else if (Const("or_b(", in)) {
2071
22
                    to_parse.emplace_back(ParseContext::OR_B, -1, -1);
2072
22
                    script_size += 2;
2073
75
                } else if (Const("or_c(", in)) {
2074
16
                    to_parse.emplace_back(ParseContext::OR_C, -1, -1);
2075
16
                    script_size += 3;
2076
59
                } else if (Const("or_d(", in)) {
2077
24
                    to_parse.emplace_back(ParseContext::OR_D, -1, -1);
2078
24
                    script_size += 4;
2079
35
                } else if (Const("or_i(", in)) {
2080
35
                    to_parse.emplace_back(ParseContext::OR_I, -1, -1);
2081
35
                    script_size += 4;
2082
35
                } else {
2083
0
                    return {};
2084
0
                }
2085
6.30k
                to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
2086
6.30k
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2087
6.30k
                to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2088
6.30k
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2089
6.30k
            }
2090
12.9k
            break;
2091
12.9k
        }
2092
12.9k
        case ParseContext::ALT: {
2093
4.48k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A, Vector(std::move(constructed.back()))};
2094
4.48k
            break;
2095
12.9k
        }
2096
21
        case ParseContext::SWAP: {
2097
21
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S, Vector(std::move(constructed.back()))};
2098
21
            break;
2099
12.9k
        }
2100
54
        case ParseContext::CHECK: {
2101
54
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(std::move(constructed.back()))};
2102
54
            break;
2103
12.9k
        }
2104
8
        case ParseContext::DUP_IF: {
2105
8
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D, Vector(std::move(constructed.back()))};
2106
8
            break;
2107
12.9k
        }
2108
8
        case ParseContext::NON_ZERO: {
2109
8
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J, Vector(std::move(constructed.back()))};
2110
8
            break;
2111
12.9k
        }
2112
15
        case ParseContext::ZERO_NOTEQUAL: {
2113
15
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N, Vector(std::move(constructed.back()))};
2114
15
            break;
2115
12.9k
        }
2116
99
        case ParseContext::VERIFY: {
2117
99
            script_size += (constructed.back().GetType() << "x"_mst);
2118
99
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V, Vector(std::move(constructed.back()))};
2119
99
            break;
2120
12.9k
        }
2121
16
        case ParseContext::WRAP_U: {
2122
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})};
2123
16
            break;
2124
12.9k
        }
2125
43
        case ParseContext::WRAP_T: {
2126
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})};
2127
43
            break;
2128
12.9k
        }
2129
4.42k
        case ParseContext::AND_B: {
2130
4.42k
            BuildBack(ctx.MsContext(), Fragment::AND_B, constructed);
2131
4.42k
            break;
2132
12.9k
        }
2133
8
        case ParseContext::AND_N: {
2134
8
            auto mid = std::move(constructed.back());
2135
8
            constructed.pop_back();
2136
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})};
2137
8
            break;
2138
12.9k
        }
2139
38
        case ParseContext::AND_V: {
2140
38
            BuildBack(ctx.MsContext(), Fragment::AND_V, constructed);
2141
38
            break;
2142
12.9k
        }
2143
21
        case ParseContext::OR_B: {
2144
21
            BuildBack(ctx.MsContext(), Fragment::OR_B, constructed);
2145
21
            break;
2146
12.9k
        }
2147
14
        case ParseContext::OR_C: {
2148
14
            BuildBack(ctx.MsContext(), Fragment::OR_C, constructed);
2149
14
            break;
2150
12.9k
        }
2151
23
        case ParseContext::OR_D: {
2152
23
            BuildBack(ctx.MsContext(), Fragment::OR_D, constructed);
2153
23
            break;
2154
12.9k
        }
2155
73
        case ParseContext::OR_I: {
2156
73
            BuildBack(ctx.MsContext(), Fragment::OR_I, constructed);
2157
73
            break;
2158
12.9k
        }
2159
29
        case ParseContext::ANDOR: {
2160
29
            auto right = std::move(constructed.back());
2161
29
            constructed.pop_back();
2162
29
            auto mid = std::move(constructed.back());
2163
29
            constructed.pop_back();
2164
29
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR, Vector(std::move(constructed.back()), std::move(mid), std::move(right))};
2165
29
            break;
2166
12.9k
        }
2167
60
        case ParseContext::THRESH: {
2168
60
            if (in.size() < 1) return {};
2169
60
            if (in[0] == ',') {
2170
39
                in = in.subspan(1);
2171
39
                to_parse.emplace_back(ParseContext::THRESH, n+1, k);
2172
39
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2173
39
                script_size += 2;
2174
39
            } else if (in[0] == ')') {
2175
21
                if (k > n) return {};
2176
19
                in = in.subspan(1);
2177
                // Children are constructed in reverse order, so iterate from end to beginning
2178
19
                std::vector<Node<Key>> subs;
2179
75
                for (int i = 0; i < n; ++i) {
2180
56
                    subs.push_back(std::move(constructed.back()));
2181
56
                    constructed.pop_back();
2182
56
                }
2183
19
                std::reverse(subs.begin(), subs.end());
2184
19
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs), k);
2185
19
            } else {
2186
0
                return {};
2187
0
            }
2188
58
            break;
2189
60
        }
2190
6.34k
        case ParseContext::COMMA: {
2191
6.34k
            if (in.size() < 1 || in[0] != ',') return {};
2192
6.34k
            in = in.subspan(1);
2193
6.34k
            break;
2194
6.34k
        }
2195
4.59k
        case ParseContext::CLOSE_BRACKET: {
2196
4.59k
            if (in.size() < 1 || in[0] != ')') return {};
2197
4.59k
            in = in.subspan(1);
2198
4.59k
            break;
2199
4.59k
        }
2200
46.2k
        }
2201
46.2k
    }
2202
2203
    // Sanity checks on the produced miniscript
2204
220
    assert(constructed.size() >= 1);
2205
188
    CHECK_NONFATAL(constructed.size() == 1);
2206
188
    assert(constructed[0].ScriptSize() == script_size);
2207
188
    if (in.size() > 0) return {};
2208
188
    Node<Key> tl_node{std::move(constructed.front())};
2209
188
    tl_node.DuplicateKeyCheck(ctx);
2210
188
    return tl_node;
2211
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
1855
533
{
1856
533
    using namespace script;
1857
1858
    // Account for the minimum script size for all parsed fragments so far. It "borrows" 1
1859
    // script byte from all leaf nodes, counting it instead whenever a space for a recursive
1860
    // expression is added (through andor, and_*, or_*, thresh). This guarantees that all fragments
1861
    // increment the script_size by at least one, except for:
1862
    // - "0", "1": these leafs are only a single byte, so their subtracted-from increment is 0.
1863
    //   This is not an issue however, as "space" for them has to be created by combinators,
1864
    //   which do increment script_size.
1865
    // - "v:": the v wrapper adds nothing as in some cases it results in no opcode being added
1866
    //   (instead transforming another opcode into its VERIFY form). However, the v: wrapper has
1867
    //   to be interleaved with other fragments to be valid, so this is not a concern.
1868
533
    size_t script_size{1};
1869
533
    size_t max_size{internal::MaxScriptSize(ctx.MsContext())};
1870
1871
    // The two integers are used to hold state for thresh()
1872
533
    std::vector<std::tuple<ParseContext, int64_t, int64_t>> to_parse;
1873
533
    std::vector<Node<Key>> constructed;
1874
1875
533
    to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
1876
1877
    // Parses a multi() or multi_a() from its string representation. Returns false on parsing error.
1878
533
    const auto parse_multi_exp = [&](std::span<const char>& in, const bool is_multi_a) -> bool {
1879
533
        const auto max_keys{is_multi_a ? MAX_PUBKEYS_PER_MULTI_A : MAX_PUBKEYS_PER_MULTISIG};
1880
533
        const auto required_ctx{is_multi_a ? MiniscriptContext::TAPSCRIPT : MiniscriptContext::P2WSH};
1881
533
        if (ctx.MsContext() != required_ctx) return false;
1882
        // Get threshold
1883
533
        int next_comma = FindNextChar(in, ',');
1884
533
        if (next_comma < 1) return false;
1885
533
        const auto k_to_integral{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
1886
533
        if (!k_to_integral.has_value()) return false;
1887
533
        const int64_t k{k_to_integral.value()};
1888
533
        in = in.subspan(next_comma + 1);
1889
        // Get keys. It is compatible for both compressed and x-only keys.
1890
533
        std::vector<Key> keys;
1891
533
        while (next_comma != -1) {
1892
533
            next_comma = FindNextChar(in, ',');
1893
533
            int key_length = (next_comma == -1) ? FindNextChar(in, ')') : next_comma;
1894
533
            if (key_length < 1) return false;
1895
533
            std::span<const char> sp{in.begin(), in.begin() + key_length};
1896
533
            auto key = ctx.FromString(sp);
1897
533
            if (!key) return false;
1898
533
            keys.push_back(std::move(*key));
1899
533
            in = in.subspan(key_length + 1);
1900
533
        }
1901
533
        if (keys.size() < 1 || keys.size() > max_keys) return false;
1902
533
        if (k < 1 || k > (int64_t)keys.size()) return false;
1903
533
        if (is_multi_a) {
1904
            // (push + xonly-key + CHECKSIG[ADD]) * n + k + OP_NUMEQUAL(VERIFY), minus one.
1905
533
            script_size += (1 + 32 + 1) * keys.size() + BuildScript(k).size();
1906
533
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), k);
1907
533
        } else {
1908
533
            script_size += 2 + (keys.size() > 16) + (k > 16) + 34 * keys.size();
1909
533
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), k);
1910
533
        }
1911
533
        return true;
1912
533
    };
1913
1914
333k
    while (!to_parse.empty()) {
1915
333k
        if (script_size > max_size) return {};
1916
1917
        // Get the current context we are decoding within
1918
333k
        auto [cur_context, n, k] = to_parse.back();
1919
333k
        to_parse.pop_back();
1920
1921
333k
        switch (cur_context) {
1922
1.21k
        case ParseContext::WRAPPED_EXPR: {
1923
1.21k
            std::optional<size_t> colon_index{};
1924
662k
            for (size_t i = 1; i < in.size(); ++i) {
1925
662k
                if (in[i] == ':') {
1926
310
                    colon_index = i;
1927
310
                    break;
1928
310
                }
1929
662k
                if (in[i] < 'a' || in[i] > 'z') break;
1930
662k
            }
1931
            // If there is no colon, this loop won't execute
1932
1.21k
            bool last_was_v{false};
1933
660k
            for (size_t j = 0; colon_index && j < *colon_index; ++j) {
1934
659k
                if (script_size > max_size) return {};
1935
659k
                if (in[j] == 'a') {
1936
82
                    script_size += 2;
1937
82
                    to_parse.emplace_back(ParseContext::ALT, -1, -1);
1938
659k
                } else if (in[j] == 's') {
1939
51
                    script_size += 1;
1940
51
                    to_parse.emplace_back(ParseContext::SWAP, -1, -1);
1941
659k
                } else if (in[j] == 'c') {
1942
16
                    script_size += 1;
1943
16
                    to_parse.emplace_back(ParseContext::CHECK, -1, -1);
1944
659k
                } else if (in[j] == 'd') {
1945
10
                    script_size += 3;
1946
10
                    to_parse.emplace_back(ParseContext::DUP_IF, -1, -1);
1947
659k
                } else if (in[j] == 'j') {
1948
0
                    script_size += 4;
1949
0
                    to_parse.emplace_back(ParseContext::NON_ZERO, -1, -1);
1950
659k
                } else if (in[j] == 'n') {
1951
658k
                    script_size += 1;
1952
658k
                    to_parse.emplace_back(ParseContext::ZERO_NOTEQUAL, -1, -1);
1953
658k
                } else if (in[j] == 'v') {
1954
                    // do not permit "...vv...:"; it's not valid, and also doesn't trigger early
1955
                    // failure as script_size isn't incremented.
1956
158
                    if (last_was_v) return {};
1957
158
                    to_parse.emplace_back(ParseContext::VERIFY, -1, -1);
1958
158
                } else if (in[j] == 'u') {
1959
0
                    script_size += 4;
1960
0
                    to_parse.emplace_back(ParseContext::WRAP_U, -1, -1);
1961
18
                } else if (in[j] == 't') {
1962
2
                    script_size += 1;
1963
2
                    to_parse.emplace_back(ParseContext::WRAP_T, -1, -1);
1964
16
                } else if (in[j] == 'l') {
1965
                    // The l: wrapper is equivalent to or_i(0,X)
1966
16
                    script_size += 4;
1967
16
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
1968
16
                    to_parse.emplace_back(ParseContext::OR_I, -1, -1);
1969
16
                } else {
1970
0
                    return {};
1971
0
                }
1972
659k
                last_was_v = (in[j] == 'v');
1973
659k
            }
1974
1.21k
            to_parse.emplace_back(ParseContext::EXPR, -1, -1);
1975
1.21k
            if (colon_index) in = in.subspan(*colon_index + 1);
1976
1.21k
            break;
1977
1.21k
        }
1978
1.21k
        case ParseContext::EXPR: {
1979
1.21k
            if (Const("0", in)) {
1980
3
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
1981
1.21k
            } else if (Const("1", in)) {
1982
3
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1);
1983
1.21k
            } else if (Const("pk(", in, /*skip=*/false)) {
1984
251
                std::optional<Key> key = ParseKey<Key, Ctx>("pk", in, ctx);
1985
251
                if (!key) return {};
1986
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)))));
1987
249
                script_size += IsTapscript(ctx.MsContext()) ? 33 : 34;
1988
961
            } else if (Const("pkh(", in, /*skip=*/false)) {
1989
82
                std::optional<Key> key = ParseKey<Key, Ctx>("pkh", in, ctx);
1990
82
                if (!key) return {};
1991
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)))));
1992
82
                script_size += 24;
1993
879
            } else if (Const("pk_k(", in, /*skip=*/false)) {
1994
25
                std::optional<Key> key = ParseKey<Key, Ctx>("pk_k", in, ctx);
1995
25
                if (!key) return {};
1996
23
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_K, Vector(std::move(*key)));
1997
23
                script_size += IsTapscript(ctx.MsContext()) ? 32 : 33;
1998
854
            } else if (Const("pk_h(", in, /*skip=*/false)) {
1999
3
                std::optional<Key> key = ParseKey<Key, Ctx>("pk_h", in, ctx);
2000
3
                if (!key) return {};
2001
3
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_H, Vector(std::move(*key)));
2002
3
                script_size += 23;
2003
851
            } else if (Const("sha256(", in, /*skip=*/false)) {
2004
8
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("sha256", in, 32, ctx);
2005
8
                if (!hash) return {};
2006
8
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, std::move(*hash));
2007
8
                script_size += 38;
2008
843
            } else if (Const("ripemd160(", in, /*skip=*/false)) {
2009
8
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("ripemd160", in, 20, ctx);
2010
8
                if (!hash) return {};
2011
8
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::RIPEMD160, std::move(*hash));
2012
8
                script_size += 26;
2013
835
            } else if (Const("hash256(", in, /*skip=*/false)) {
2014
8
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("hash256", in, 32, ctx);
2015
8
                if (!hash) return {};
2016
8
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, std::move(*hash));
2017
8
                script_size += 38;
2018
827
            } else if (Const("hash160(", in, /*skip=*/false)) {
2019
16
                std::optional<std::vector<unsigned char>> hash = ParseHexStr("hash160", in, 20, ctx);
2020
16
                if (!hash) return {};
2021
16
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, std::move(*hash));
2022
16
                script_size += 26;
2023
811
            } else if (Const("after(", in, /*skip=*/false)) {
2024
49
                auto expr = Expr(in);
2025
49
                if (!Func("after", expr)) return {};
2026
49
                const auto num{ToIntegral<int64_t>(std::string_view(expr.begin(), expr.end()))};
2027
49
                if (!num.has_value() || *num < 1 || *num >= 0x80000000L) return {};
2028
49
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num);
2029
49
                script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
2030
762
            } else if (Const("older(", in, /*skip=*/false)) {
2031
73
                auto expr = Expr(in);
2032
73
                if (!Func("older", expr)) return {};
2033
73
                const auto num{ToIntegral<int64_t>(std::string_view(expr.begin(), expr.end()))};
2034
73
                if (!num.has_value() || *num < 1 || *num >= 0x80000000L) return {};
2035
73
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num);
2036
73
                script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
2037
689
            } else if (Const("multi(", in)) {
2038
18
                if (!parse_multi_exp(in, /* is_multi_a = */false)) return {};
2039
671
            } else if (Const("multi_a(", in)) {
2040
14
                if (!parse_multi_exp(in, /* is_multi_a = */true)) return {};
2041
657
            } else if (Const("thresh(", in)) {
2042
33
                int next_comma = FindNextChar(in, ',');
2043
33
                if (next_comma < 1) return {};
2044
33
                const auto k{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
2045
33
                if (!k.has_value() || *k < 1) return {};
2046
33
                in = in.subspan(next_comma + 1);
2047
                // n = 1 here because we read the first WRAPPED_EXPR before reaching THRESH
2048
33
                to_parse.emplace_back(ParseContext::THRESH, 1, *k);
2049
33
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2050
33
                script_size += 2 + (*k > 16) + (*k > 0x7f) + (*k > 0x7fff) + (*k > 0x7fffff);
2051
624
            } else if (Const("andor(", in)) {
2052
25
                to_parse.emplace_back(ParseContext::ANDOR, -1, -1);
2053
25
                to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
2054
25
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2055
25
                to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2056
25
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2057
25
                to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2058
25
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2059
25
                script_size += 5;
2060
599
            } else {
2061
599
                if (Const("and_n(", in)) {
2062
8
                    to_parse.emplace_back(ParseContext::AND_N, -1, -1);
2063
8
                    script_size += 5;
2064
591
                } else if (Const("and_b(", in)) {
2065
41
                    to_parse.emplace_back(ParseContext::AND_B, -1, -1);
2066
41
                    script_size += 2;
2067
550
                } else if (Const("and_v(", in)) {
2068
142
                    to_parse.emplace_back(ParseContext::AND_V, -1, -1);
2069
142
                    script_size += 1;
2070
408
                } else if (Const("or_b(", in)) {
2071
23
                    to_parse.emplace_back(ParseContext::OR_B, -1, -1);
2072
23
                    script_size += 2;
2073
385
                } else if (Const("or_c(", in)) {
2074
12
                    to_parse.emplace_back(ParseContext::OR_C, -1, -1);
2075
12
                    script_size += 3;
2076
373
                } else if (Const("or_d(", in)) {
2077
18
                    to_parse.emplace_back(ParseContext::OR_D, -1, -1);
2078
18
                    script_size += 4;
2079
355
                } else if (Const("or_i(", in)) {
2080
10
                    to_parse.emplace_back(ParseContext::OR_I, -1, -1);
2081
10
                    script_size += 4;
2082
345
                } else {
2083
345
                    return {};
2084
345
                }
2085
254
                to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
2086
254
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2087
254
                to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2088
254
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2089
254
            }
2090
868
            break;
2091
1.21k
        }
2092
868
        case ParseContext::ALT: {
2093
82
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A, Vector(std::move(constructed.back()))};
2094
82
            break;
2095
1.21k
        }
2096
51
        case ParseContext::SWAP: {
2097
51
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S, Vector(std::move(constructed.back()))};
2098
51
            break;
2099
1.21k
        }
2100
14
        case ParseContext::CHECK: {
2101
14
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(std::move(constructed.back()))};
2102
14
            break;
2103
1.21k
        }
2104
10
        case ParseContext::DUP_IF: {
2105
10
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D, Vector(std::move(constructed.back()))};
2106
10
            break;
2107
1.21k
        }
2108
0
        case ParseContext::NON_ZERO: {
2109
0
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J, Vector(std::move(constructed.back()))};
2110
0
            break;
2111
1.21k
        }
2112
329k
        case ParseContext::ZERO_NOTEQUAL: {
2113
329k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N, Vector(std::move(constructed.back()))};
2114
329k
            break;
2115
1.21k
        }
2116
156
        case ParseContext::VERIFY: {
2117
156
            script_size += (constructed.back().GetType() << "x"_mst);
2118
156
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V, Vector(std::move(constructed.back()))};
2119
156
            break;
2120
1.21k
        }
2121
0
        case ParseContext::WRAP_U: {
2122
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})};
2123
0
            break;
2124
1.21k
        }
2125
2
        case ParseContext::WRAP_T: {
2126
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})};
2127
2
            break;
2128
1.21k
        }
2129
41
        case ParseContext::AND_B: {
2130
41
            BuildBack(ctx.MsContext(), Fragment::AND_B, constructed);
2131
41
            break;
2132
1.21k
        }
2133
8
        case ParseContext::AND_N: {
2134
8
            auto mid = std::move(constructed.back());
2135
8
            constructed.pop_back();
2136
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})};
2137
8
            break;
2138
1.21k
        }
2139
138
        case ParseContext::AND_V: {
2140
138
            BuildBack(ctx.MsContext(), Fragment::AND_V, constructed);
2141
138
            break;
2142
1.21k
        }
2143
23
        case ParseContext::OR_B: {
2144
23
            BuildBack(ctx.MsContext(), Fragment::OR_B, constructed);
2145
23
            break;
2146
1.21k
        }
2147
12
        case ParseContext::OR_C: {
2148
12
            BuildBack(ctx.MsContext(), Fragment::OR_C, constructed);
2149
12
            break;
2150
1.21k
        }
2151
18
        case ParseContext::OR_D: {
2152
18
            BuildBack(ctx.MsContext(), Fragment::OR_D, constructed);
2153
18
            break;
2154
1.21k
        }
2155
26
        case ParseContext::OR_I: {
2156
26
            BuildBack(ctx.MsContext(), Fragment::OR_I, constructed);
2157
26
            break;
2158
1.21k
        }
2159
23
        case ParseContext::ANDOR: {
2160
23
            auto right = std::move(constructed.back());
2161
23
            constructed.pop_back();
2162
23
            auto mid = std::move(constructed.back());
2163
23
            constructed.pop_back();
2164
23
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR, Vector(std::move(constructed.back()), std::move(mid), std::move(right))};
2165
23
            break;
2166
1.21k
        }
2167
104
        case ParseContext::THRESH: {
2168
104
            if (in.size() < 1) return {};
2169
104
            if (in[0] == ',') {
2170
71
                in = in.subspan(1);
2171
71
                to_parse.emplace_back(ParseContext::THRESH, n+1, k);
2172
71
                to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2173
71
                script_size += 2;
2174
71
            } else if (in[0] == ')') {
2175
33
                if (k > n) return {};
2176
33
                in = in.subspan(1);
2177
                // Children are constructed in reverse order, so iterate from end to beginning
2178
33
                std::vector<Node<Key>> subs;
2179
137
                for (int i = 0; i < n; ++i) {
2180
104
                    subs.push_back(std::move(constructed.back()));
2181
104
                    constructed.pop_back();
2182
104
                }
2183
33
                std::reverse(subs.begin(), subs.end());
2184
33
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs), k);
2185
33
            } else {
2186
0
                return {};
2187
0
            }
2188
104
            break;
2189
104
        }
2190
302
        case ParseContext::COMMA: {
2191
302
            if (in.size() < 1 || in[0] != ',') return {};
2192
302
            in = in.subspan(1);
2193
302
            break;
2194
302
        }
2195
273
        case ParseContext::CLOSE_BRACKET: {
2196
273
            if (in.size() < 1 || in[0] != ')') return {};
2197
273
            in = in.subspan(1);
2198
273
            break;
2199
273
        }
2200
333k
        }
2201
333k
    }
2202
2203
    // Sanity checks on the produced miniscript
2204
533
    assert(constructed.size() >= 1);
2205
182
    CHECK_NONFATAL(constructed.size() == 1);
2206
182
    assert(constructed[0].ScriptSize() == script_size);
2207
182
    if (in.size() > 0) return {};
2208
179
    Node<Key> tl_node{std::move(constructed.front())};
2209
179
    tl_node.DuplicateKeyCheck(ctx);
2210
179
    return tl_node;
2211
182
}
2212
2213
/** Decode a script into opcode/push pairs.
2214
 *
2215
 * Construct a vector with one element per opcode in the script, in reverse order.
2216
 * Each element is a pair consisting of the opcode, as well as the data pushed by
2217
 * the opcode (including OP_n), if any. OP_CHECKSIGVERIFY, OP_CHECKMULTISIGVERIFY,
2218
 * OP_NUMEQUALVERIFY and OP_EQUALVERIFY are decomposed into OP_CHECKSIG, OP_CHECKMULTISIG,
2219
 * OP_EQUAL and OP_NUMEQUAL respectively, plus OP_VERIFY.
2220
 */
2221
std::optional<std::vector<Opcode>> DecomposeScript(const CScript& script);
2222
2223
/** Determine whether the passed pair (created by DecomposeScript) is pushing a number. */
2224
std::optional<int64_t> ParseScriptNumber(const Opcode& in);
2225
2226
enum class DecodeContext {
2227
    /** A single expression of type B, K, or V. Specifically, this can't be an
2228
     * and_v or an expression of type W (a: and s: wrappers). */
2229
    SINGLE_BKV_EXPR,
2230
    /** Potentially multiple SINGLE_BKV_EXPRs as children of (potentially multiple)
2231
     * and_v expressions. Syntactic sugar for MAYBE_AND_V + SINGLE_BKV_EXPR. */
2232
    BKV_EXPR,
2233
    /** An expression of type W (a: or s: wrappers). */
2234
    W_EXPR,
2235
2236
    /** SWAP expects the next element to be OP_SWAP (inside a W-type expression that
2237
     * didn't end with FROMALTSTACK), and wraps the top of the constructed stack
2238
     * with s: */
2239
    SWAP,
2240
    /** ALT expects the next element to be TOALTSTACK (we must have already read a
2241
     * FROMALTSTACK earlier), and wraps the top of the constructed stack with a: */
2242
    ALT,
2243
    /** CHECK wraps the top constructed node with c: */
2244
    CHECK,
2245
    /** DUP_IF wraps the top constructed node with d: */
2246
    DUP_IF,
2247
    /** VERIFY wraps the top constructed node with v: */
2248
    VERIFY,
2249
    /** NON_ZERO wraps the top constructed node with j: */
2250
    NON_ZERO,
2251
    /** ZERO_NOTEQUAL wraps the top constructed node with n: */
2252
    ZERO_NOTEQUAL,
2253
2254
    /** MAYBE_AND_V will check if the next part of the script could be a valid
2255
     * miniscript sub-expression, and if so it will push AND_V and SINGLE_BKV_EXPR
2256
     * to decode it and construct the and_v node. This is recursive, to deal with
2257
     * multiple and_v nodes inside each other. */
2258
    MAYBE_AND_V,
2259
    /** AND_V will construct an and_v node from the last two constructed nodes. */
2260
    AND_V,
2261
    /** AND_B will construct an and_b node from the last two constructed nodes. */
2262
    AND_B,
2263
    /** ANDOR will construct an andor node from the last three constructed nodes. */
2264
    ANDOR,
2265
    /** OR_B will construct an or_b node from the last two constructed nodes. */
2266
    OR_B,
2267
    /** OR_C will construct an or_c node from the last two constructed nodes. */
2268
    OR_C,
2269
    /** OR_D will construct an or_d node from the last two constructed nodes. */
2270
    OR_D,
2271
2272
    /** In a thresh expression, all sub-expressions other than the first are W-type,
2273
     * and end in OP_ADD. THRESH_W will check for this OP_ADD and either push a W_EXPR
2274
     * or a SINGLE_BKV_EXPR and jump to THRESH_E accordingly. */
2275
    THRESH_W,
2276
    /** THRESH_E constructs a thresh node from the appropriate number of constructed
2277
     * children. */
2278
    THRESH_E,
2279
2280
    /** ENDIF signals that we are inside some sort of OP_IF structure, which could be
2281
     * or_d, or_c, or_i, andor, d:, or j: wrapper, depending on what follows. We read
2282
     * a BKV_EXPR and then deal with the next opcode case-by-case. */
2283
    ENDIF,
2284
    /** If, inside an ENDIF context, we find an OP_NOTIF before finding an OP_ELSE,
2285
     * we could either be in an or_d or an or_c node. We then check for IFDUP to
2286
     * distinguish these cases. */
2287
    ENDIF_NOTIF,
2288
    /** If, inside an ENDIF context, we find an OP_ELSE, then we could be in either an
2289
     * or_i or an andor node. Read the next BKV_EXPR and find either an OP_IF or an
2290
     * OP_NOTIF. */
2291
    ENDIF_ELSE,
2292
};
2293
2294
//! Parse a miniscript from a bitcoin script
2295
template <typename Key, typename Ctx, typename I>
2296
inline std::optional<Node<Key>> DecodeScript(I& in, I last, const Ctx& ctx)
2297
4.02k
{
2298
    // The two integers are used to hold state for thresh()
2299
4.02k
    std::vector<std::tuple<DecodeContext, int64_t, int64_t>> to_parse;
2300
4.02k
    std::vector<Node<Key>> constructed;
2301
2302
    // This is the top level, so we assume the type is B
2303
    // (in particular, disallowing top level W expressions)
2304
4.02k
    to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2305
2306
11.9M
    while (!to_parse.empty()) {
2307
        // Exit early if the Miniscript is not going to be valid.
2308
11.9M
        if (!constructed.empty() && !constructed.back().IsValid()) return {};
2309
2310
        // Get the current context we are decoding within
2311
11.9M
        auto [cur_context, n, k] = to_parse.back();
2312
11.9M
        to_parse.pop_back();
2313
2314
11.9M
        switch(cur_context) {
2315
5.94M
        case DecodeContext::SINGLE_BKV_EXPR: {
2316
5.94M
            if (in >= last) return {};
2317
2318
            // Constants
2319
5.94M
            if (in[0].first == OP_1) {
2320
80
                ++in;
2321
80
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1);
2322
80
                break;
2323
80
            }
2324
5.94M
            if (in[0].first == OP_0) {
2325
519
                ++in;
2326
519
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
2327
519
                break;
2328
519
            }
2329
            // Public keys
2330
5.94M
            if (in[0].second.size() == 33 || in[0].second.size() == 32) {
2331
4.05k
                auto key = ctx.FromPKBytes(in[0].second.begin(), in[0].second.end());
2332
4.05k
                if (!key) return {};
2333
4.05k
                ++in;
2334
4.05k
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_K, Vector(std::move(*key)));
2335
4.05k
                break;
2336
4.05k
            }
2337
5.94M
            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) {
2338
571
                auto key = ctx.FromPKHBytes(in[2].second.begin(), in[2].second.end());
2339
571
                if (!key) return {};
2340
568
                in += 5;
2341
568
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_H, Vector(std::move(*key)));
2342
568
                break;
2343
571
            }
2344
            // Time locks
2345
5.94M
            std::optional<int64_t> num;
2346
5.94M
            if (last - in >= 2 && in[0].first == OP_CHECKSEQUENCEVERIFY && (num = ParseScriptNumber(in[1]))) {
2347
2.33k
                in += 2;
2348
2.33k
                if (*num < 1 || *num > 0x7FFFFFFFL) return {};
2349
2.33k
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num);
2350
2.33k
                break;
2351
2.33k
            }
2352
5.94M
            if (last - in >= 2 && in[0].first == OP_CHECKLOCKTIMEVERIFY && (num = ParseScriptNumber(in[1]))) {
2353
922
                in += 2;
2354
922
                if (num < 1 || num > 0x7FFFFFFFL) return {};
2355
922
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num);
2356
922
                break;
2357
922
            }
2358
            // Hashes
2359
5.94M
            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) {
2360
269
                if (in[2].first == OP_SHA256 && in[1].second.size() == 32) {
2361
67
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, in[1].second);
2362
67
                    in += 7;
2363
67
                    break;
2364
202
                } else if (in[2].first == OP_RIPEMD160 && in[1].second.size() == 20) {
2365
55
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::RIPEMD160, in[1].second);
2366
55
                    in += 7;
2367
55
                    break;
2368
147
                } else if (in[2].first == OP_HASH256 && in[1].second.size() == 32) {
2369
86
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, in[1].second);
2370
86
                    in += 7;
2371
86
                    break;
2372
86
                } else if (in[2].first == OP_HASH160 && in[1].second.size() == 20) {
2373
61
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, in[1].second);
2374
61
                    in += 7;
2375
61
                    break;
2376
61
                }
2377
269
            }
2378
            // Multi
2379
5.94M
            if (last - in >= 3 && in[0].first == OP_CHECKMULTISIG) {
2380
130
                if (IsTapscript(ctx.MsContext())) return {};
2381
130
                std::vector<Key> keys;
2382
130
                const auto n = ParseScriptNumber(in[1]);
2383
130
                if (!n || last - in < 3 + *n) return {};
2384
130
                if (*n < 1 || *n > 20) return {};
2385
435
                for (int i = 0; i < *n; ++i) {
2386
305
                    if (in[2 + i].second.size() != 33) return {};
2387
305
                    auto key = ctx.FromPKBytes(in[2 + i].second.begin(), in[2 + i].second.end());
2388
305
                    if (!key) return {};
2389
305
                    keys.push_back(std::move(*key));
2390
305
                }
2391
130
                const auto k = ParseScriptNumber(in[2 + *n]);
2392
130
                if (!k || *k < 1 || *k > *n) return {};
2393
130
                in += 3 + *n;
2394
130
                std::reverse(keys.begin(), keys.end());
2395
130
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), *k);
2396
130
                break;
2397
130
            }
2398
            // Tapscript's equivalent of multi
2399
5.94M
            if (last - in >= 4 && in[0].first == OP_NUMEQUAL) {
2400
779
                if (!IsTapscript(ctx.MsContext())) return {};
2401
                // The necessary threshold of signatures.
2402
779
                const auto k = ParseScriptNumber(in[1]);
2403
779
                if (!k) return {};
2404
779
                if (*k < 1 || *k > MAX_PUBKEYS_PER_MULTI_A) return {};
2405
779
                if (last - in < 2 + *k * 2) return {};
2406
779
                std::vector<Key> keys;
2407
779
                keys.reserve(*k);
2408
                // Walk through the expected (pubkey, CHECKSIG[ADD]) pairs.
2409
90.5k
                for (int pos = 2;; pos += 2) {
2410
90.5k
                    if (last - in < pos + 2) return {};
2411
                    // Make sure it's indeed an x-only pubkey and a CHECKSIG[ADD], then parse the key.
2412
90.5k
                    if (in[pos].first != OP_CHECKSIGADD && in[pos].first != OP_CHECKSIG) return {};
2413
90.5k
                    if (in[pos + 1].second.size() != 32) return {};
2414
90.5k
                    auto key = ctx.FromPKBytes(in[pos + 1].second.begin(), in[pos + 1].second.end());
2415
90.5k
                    if (!key) return {};
2416
90.5k
                    keys.push_back(std::move(*key));
2417
                    // Make sure early we don't parse an arbitrary large expression.
2418
90.5k
                    if (keys.size() > MAX_PUBKEYS_PER_MULTI_A) return {};
2419
                    // OP_CHECKSIG means it was the last one to parse.
2420
90.5k
                    if (in[pos].first == OP_CHECKSIG) break;
2421
90.5k
                }
2422
778
                if (keys.size() < (size_t)*k) return {};
2423
778
                in += 2 + keys.size() * 2;
2424
778
                std::reverse(keys.begin(), keys.end());
2425
778
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), *k);
2426
778
                break;
2427
778
            }
2428
            /** In the following wrappers, we only need to push SINGLE_BKV_EXPR rather
2429
             * than BKV_EXPR, because and_v commutes with these wrappers. For example,
2430
             * c:and_v(X,Y) produces the same script as and_v(X,c:Y). */
2431
            // c: wrapper
2432
5.94M
            if (in[0].first == OP_CHECKSIG) {
2433
4.59k
                ++in;
2434
4.59k
                to_parse.emplace_back(DecodeContext::CHECK, -1, -1);
2435
4.59k
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2436
4.59k
                break;
2437
4.59k
            }
2438
            // v: wrapper
2439
5.93M
            if (in[0].first == OP_VERIFY) {
2440
1.19k
                ++in;
2441
1.19k
                to_parse.emplace_back(DecodeContext::VERIFY, -1, -1);
2442
1.19k
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2443
1.19k
                break;
2444
1.19k
            }
2445
            // n: wrapper
2446
5.93M
            if (in[0].first == OP_0NOTEQUAL) {
2447
5.93M
                ++in;
2448
5.93M
                to_parse.emplace_back(DecodeContext::ZERO_NOTEQUAL, -1, -1);
2449
5.93M
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2450
5.93M
                break;
2451
5.93M
            }
2452
            // Thresh
2453
3.85k
            if (last - in >= 3 && in[0].first == OP_EQUAL && (num = ParseScriptNumber(in[1]))) {
2454
317
                if (*num < 1) return {};
2455
317
                in += 2;
2456
317
                to_parse.emplace_back(DecodeContext::THRESH_W, 0, *num);
2457
317
                break;
2458
317
            }
2459
            // OP_ENDIF can be WRAP_J, WRAP_D, ANDOR, OR_C, OR_D, or OR_I
2460
3.53k
            if (in[0].first == OP_ENDIF) {
2461
838
                ++in;
2462
838
                to_parse.emplace_back(DecodeContext::ENDIF, -1, -1);
2463
838
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2464
838
                break;
2465
838
            }
2466
            /** In and_b and or_b nodes, we only look for SINGLE_BKV_EXPR, because
2467
             * or_b(and_v(X,Y),Z) has script [X] [Y] [Z] OP_BOOLOR, the same as
2468
             * and_v(X,or_b(Y,Z)). In this example, the former of these is invalid as
2469
             * miniscript, while the latter is valid. So we leave the and_v "outside"
2470
             * while decoding. */
2471
            // and_b
2472
2.69k
            if (in[0].first == OP_BOOLAND) {
2473
2.65k
                ++in;
2474
2.65k
                to_parse.emplace_back(DecodeContext::AND_B, -1, -1);
2475
2.65k
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2476
2.65k
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2477
2.65k
                break;
2478
2.65k
            }
2479
            // or_b
2480
40
            if (in[0].first == OP_BOOLOR) {
2481
30
                ++in;
2482
30
                to_parse.emplace_back(DecodeContext::OR_B, -1, -1);
2483
30
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2484
30
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2485
30
                break;
2486
30
            }
2487
            // Unrecognised expression
2488
10
            return {};
2489
40
        }
2490
10.2k
        case DecodeContext::BKV_EXPR: {
2491
10.2k
            to_parse.emplace_back(DecodeContext::MAYBE_AND_V, -1, -1);
2492
10.2k
            to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2493
10.2k
            break;
2494
40
        }
2495
3.65k
        case DecodeContext::W_EXPR: {
2496
            // a: wrapper
2497
3.65k
            if (in >= last) return {};
2498
3.65k
            if (in[0].first == OP_FROMALTSTACK) {
2499
2.90k
                ++in;
2500
2.90k
                to_parse.emplace_back(DecodeContext::ALT, -1, -1);
2501
2.90k
            } else {
2502
752
                to_parse.emplace_back(DecodeContext::SWAP, -1, -1);
2503
752
            }
2504
3.65k
            to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2505
3.65k
            break;
2506
3.65k
        }
2507
10.2k
        case DecodeContext::MAYBE_AND_V: {
2508
            // If we reach a potential AND_V top-level, check if the next part of the script could be another AND_V child
2509
            // These op-codes cannot end any well-formed miniscript so cannot be used in an and_v node.
2510
10.2k
            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) {
2511
1.09k
                to_parse.emplace_back(DecodeContext::AND_V, -1, -1);
2512
                // BKV_EXPR can contain more AND_V nodes
2513
1.09k
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2514
1.09k
            }
2515
10.2k
            break;
2516
3.65k
        }
2517
752
        case DecodeContext::SWAP: {
2518
752
            if (in >= last || in[0].first != OP_SWAP || constructed.empty()) return {};
2519
752
            ++in;
2520
752
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S, Vector(std::move(constructed.back()))};
2521
752
            break;
2522
752
        }
2523
2.90k
        case DecodeContext::ALT: {
2524
2.90k
            if (in >= last || in[0].first != OP_TOALTSTACK || constructed.empty()) return {};
2525
2.90k
            ++in;
2526
2.90k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A, Vector(std::move(constructed.back()))};
2527
2.90k
            break;
2528
2.90k
        }
2529
4.58k
        case DecodeContext::CHECK: {
2530
4.58k
            if (constructed.empty()) return {};
2531
4.58k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(std::move(constructed.back()))};
2532
4.58k
            break;
2533
4.58k
        }
2534
87
        case DecodeContext::DUP_IF: {
2535
87
            if (constructed.empty()) return {};
2536
87
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D, Vector(std::move(constructed.back()))};
2537
87
            break;
2538
87
        }
2539
1.19k
        case DecodeContext::VERIFY: {
2540
1.19k
            if (constructed.empty()) return {};
2541
1.19k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V, Vector(std::move(constructed.back()))};
2542
1.19k
            break;
2543
1.19k
        }
2544
8
        case DecodeContext::NON_ZERO: {
2545
8
            if (constructed.empty()) return {};
2546
8
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J, Vector(std::move(constructed.back()))};
2547
8
            break;
2548
8
        }
2549
5.93M
        case DecodeContext::ZERO_NOTEQUAL: {
2550
5.93M
            if (constructed.empty()) return {};
2551
5.93M
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N, Vector(std::move(constructed.back()))};
2552
5.93M
            break;
2553
5.93M
        }
2554
1.09k
        case DecodeContext::AND_V: {
2555
1.09k
            if (constructed.size() < 2) return {};
2556
1.09k
            BuildBack(ctx.MsContext(), Fragment::AND_V, constructed, /*reverse=*/true);
2557
1.09k
            break;
2558
1.09k
        }
2559
2.65k
        case DecodeContext::AND_B: {
2560
2.65k
            if (constructed.size() < 2) return {};
2561
2.65k
            BuildBack(ctx.MsContext(), Fragment::AND_B, constructed, /*reverse=*/true);
2562
2.65k
            break;
2563
2.65k
        }
2564
30
        case DecodeContext::OR_B: {
2565
30
            if (constructed.size() < 2) return {};
2566
30
            BuildBack(ctx.MsContext(), Fragment::OR_B, constructed, /*reverse=*/true);
2567
30
            break;
2568
30
        }
2569
24
        case DecodeContext::OR_C: {
2570
24
            if (constructed.size() < 2) return {};
2571
24
            BuildBack(ctx.MsContext(), Fragment::OR_C, constructed, /*reverse=*/true);
2572
24
            break;
2573
24
        }
2574
68
        case DecodeContext::OR_D: {
2575
68
            if (constructed.size() < 2) return {};
2576
68
            BuildBack(ctx.MsContext(), Fragment::OR_D, constructed, /*reverse=*/true);
2577
68
            break;
2578
68
        }
2579
158
        case DecodeContext::ANDOR: {
2580
158
            if (constructed.size() < 3) return {};
2581
158
            Node left{std::move(constructed.back())};
2582
158
            constructed.pop_back();
2583
158
            Node right{std::move(constructed.back())};
2584
158
            constructed.pop_back();
2585
158
            Node mid{std::move(constructed.back())};
2586
158
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR, Vector(std::move(left), std::move(mid), std::move(right))};
2587
158
            break;
2588
158
        }
2589
1.28k
        case DecodeContext::THRESH_W: {
2590
1.28k
            if (in >= last) return {};
2591
1.28k
            if (in[0].first == OP_ADD) {
2592
966
                ++in;
2593
966
                to_parse.emplace_back(DecodeContext::THRESH_W, n+1, k);
2594
966
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2595
966
            } else {
2596
317
                to_parse.emplace_back(DecodeContext::THRESH_E, n+1, k);
2597
                // All children of thresh have type modifier d, so cannot be and_v
2598
317
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2599
317
            }
2600
1.28k
            break;
2601
1.28k
        }
2602
317
        case DecodeContext::THRESH_E: {
2603
317
            if (k < 1 || k > n || constructed.size() < static_cast<size_t>(n)) return {};
2604
317
            std::vector<Node<Key>> subs;
2605
1.60k
            for (int i = 0; i < n; ++i) {
2606
1.28k
                Node sub{std::move(constructed.back())};
2607
1.28k
                constructed.pop_back();
2608
1.28k
                subs.push_back(std::move(sub));
2609
1.28k
            }
2610
317
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs), k);
2611
317
            break;
2612
317
        }
2613
837
        case DecodeContext::ENDIF: {
2614
837
            if (in >= last) return {};
2615
2616
            // could be andor or or_i
2617
837
            if (in[0].first == OP_ELSE) {
2618
650
                ++in;
2619
650
                to_parse.emplace_back(DecodeContext::ENDIF_ELSE, -1, -1);
2620
650
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2621
650
            }
2622
            // could be j: or d: wrapper
2623
187
            else if (in[0].first == OP_IF) {
2624
95
                if (last - in >= 2 && in[1].first == OP_DUP) {
2625
87
                    in += 2;
2626
87
                    to_parse.emplace_back(DecodeContext::DUP_IF, -1, -1);
2627
87
                } else if (last - in >= 3 && in[1].first == OP_0NOTEQUAL && in[2].first == OP_SIZE) {
2628
8
                    in += 3;
2629
8
                    to_parse.emplace_back(DecodeContext::NON_ZERO, -1, -1);
2630
8
                }
2631
0
                else {
2632
0
                    return {};
2633
0
                }
2634
            // could be or_c or or_d
2635
95
            } else if (in[0].first == OP_NOTIF) {
2636
92
                ++in;
2637
92
                to_parse.emplace_back(DecodeContext::ENDIF_NOTIF, -1, -1);
2638
92
            }
2639
0
            else {
2640
0
                return {};
2641
0
            }
2642
837
            break;
2643
837
        }
2644
837
        case DecodeContext::ENDIF_NOTIF: {
2645
92
            if (in >= last) return {};
2646
92
            if (in[0].first == OP_IFDUP) {
2647
68
                ++in;
2648
68
                to_parse.emplace_back(DecodeContext::OR_D, -1, -1);
2649
68
            } else {
2650
24
                to_parse.emplace_back(DecodeContext::OR_C, -1, -1);
2651
24
            }
2652
            // or_c and or_d both require X to have type modifier d so, can't contain and_v
2653
92
            to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2654
92
            break;
2655
92
        }
2656
650
        case DecodeContext::ENDIF_ELSE: {
2657
650
            if (in >= last) return {};
2658
650
            if (in[0].first == OP_IF) {
2659
492
                ++in;
2660
492
                BuildBack(ctx.MsContext(), Fragment::OR_I, constructed, /*reverse=*/true);
2661
492
            } else if (in[0].first == OP_NOTIF) {
2662
158
                ++in;
2663
158
                to_parse.emplace_back(DecodeContext::ANDOR, -1, -1);
2664
                // andor requires X to have type modifier d, so it can't be and_v
2665
158
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2666
158
            } else {
2667
0
                return {};
2668
0
            }
2669
650
            break;
2670
650
        }
2671
11.9M
        }
2672
11.9M
    }
2673
4.00k
    if (constructed.size() != 1) return {};
2674
4.00k
    Node tl_node{std::move(constructed.front())};
2675
4.00k
    tl_node.DuplicateKeyCheck(ctx);
2676
    // Note that due to how ComputeType works (only assign the type to the node if the
2677
    // subs' types are valid) this would fail if any node of tree is badly typed.
2678
4.00k
    if (!tl_node.IsValidTopLevel()) return {};
2679
4.00k
    return tl_node;
2680
4.00k
}
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
2297
128
{
2298
    // The two integers are used to hold state for thresh()
2299
128
    std::vector<std::tuple<DecodeContext, int64_t, int64_t>> to_parse;
2300
128
    std::vector<Node<Key>> constructed;
2301
2302
    // This is the top level, so we assume the type is B
2303
    // (in particular, disallowing top level W expressions)
2304
128
    to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2305
2306
20.2k
    while (!to_parse.empty()) {
2307
        // Exit early if the Miniscript is not going to be valid.
2308
20.1k
        if (!constructed.empty() && !constructed.back().IsValid()) return {};
2309
2310
        // Get the current context we are decoding within
2311
20.1k
        auto [cur_context, n, k] = to_parse.back();
2312
20.1k
        to_parse.pop_back();
2313
2314
20.1k
        switch(cur_context) {
2315
5.95k
        case DecodeContext::SINGLE_BKV_EXPR: {
2316
5.95k
            if (in >= last) return {};
2317
2318
            // Constants
2319
5.95k
            if (in[0].first == OP_1) {
2320
77
                ++in;
2321
77
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1);
2322
77
                break;
2323
77
            }
2324
5.87k
            if (in[0].first == OP_0) {
2325
83
                ++in;
2326
83
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
2327
83
                break;
2328
83
            }
2329
            // Public keys
2330
5.79k
            if (in[0].second.size() == 33 || in[0].second.size() == 32) {
2331
454
                auto key = ctx.FromPKBytes(in[0].second.begin(), in[0].second.end());
2332
454
                if (!key) return {};
2333
454
                ++in;
2334
454
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_K, Vector(std::move(*key)));
2335
454
                break;
2336
454
            }
2337
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) {
2338
26
                auto key = ctx.FromPKHBytes(in[2].second.begin(), in[2].second.end());
2339
26
                if (!key) return {};
2340
26
                in += 5;
2341
26
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_H, Vector(std::move(*key)));
2342
26
                break;
2343
26
            }
2344
            // Time locks
2345
5.31k
            std::optional<int64_t> num;
2346
5.31k
            if (last - in >= 2 && in[0].first == OP_CHECKSEQUENCEVERIFY && (num = ParseScriptNumber(in[1]))) {
2347
2.03k
                in += 2;
2348
2.03k
                if (*num < 1 || *num > 0x7FFFFFFFL) return {};
2349
2.03k
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num);
2350
2.03k
                break;
2351
2.03k
            }
2352
3.27k
            if (last - in >= 2 && in[0].first == OP_CHECKLOCKTIMEVERIFY && (num = ParseScriptNumber(in[1]))) {
2353
65
                in += 2;
2354
65
                if (num < 1 || num > 0x7FFFFFFFL) return {};
2355
65
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num);
2356
65
                break;
2357
65
            }
2358
            // Hashes
2359
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) {
2360
48
                if (in[2].first == OP_SHA256 && in[1].second.size() == 32) {
2361
21
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, in[1].second);
2362
21
                    in += 7;
2363
21
                    break;
2364
27
                } else if (in[2].first == OP_RIPEMD160 && in[1].second.size() == 20) {
2365
7
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::RIPEMD160, in[1].second);
2366
7
                    in += 7;
2367
7
                    break;
2368
20
                } else if (in[2].first == OP_HASH256 && in[1].second.size() == 32) {
2369
14
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, in[1].second);
2370
14
                    in += 7;
2371
14
                    break;
2372
14
                } else if (in[2].first == OP_HASH160 && in[1].second.size() == 20) {
2373
6
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, in[1].second);
2374
6
                    in += 7;
2375
6
                    break;
2376
6
                }
2377
48
            }
2378
            // Multi
2379
3.16k
            if (last - in >= 3 && in[0].first == OP_CHECKMULTISIG) {
2380
12
                if (IsTapscript(ctx.MsContext())) return {};
2381
12
                std::vector<Key> keys;
2382
12
                const auto n = ParseScriptNumber(in[1]);
2383
12
                if (!n || last - in < 3 + *n) return {};
2384
12
                if (*n < 1 || *n > 20) return {};
2385
35
                for (int i = 0; i < *n; ++i) {
2386
23
                    if (in[2 + i].second.size() != 33) return {};
2387
23
                    auto key = ctx.FromPKBytes(in[2 + i].second.begin(), in[2 + i].second.end());
2388
23
                    if (!key) return {};
2389
23
                    keys.push_back(std::move(*key));
2390
23
                }
2391
12
                const auto k = ParseScriptNumber(in[2 + *n]);
2392
12
                if (!k || *k < 1 || *k > *n) return {};
2393
12
                in += 3 + *n;
2394
12
                std::reverse(keys.begin(), keys.end());
2395
12
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), *k);
2396
12
                break;
2397
12
            }
2398
            // Tapscript's equivalent of multi
2399
3.15k
            if (last - in >= 4 && in[0].first == OP_NUMEQUAL) {
2400
4
                if (!IsTapscript(ctx.MsContext())) return {};
2401
                // The necessary threshold of signatures.
2402
4
                const auto k = ParseScriptNumber(in[1]);
2403
4
                if (!k) return {};
2404
4
                if (*k < 1 || *k > MAX_PUBKEYS_PER_MULTI_A) return {};
2405
4
                if (last - in < 2 + *k * 2) return {};
2406
4
                std::vector<Key> keys;
2407
4
                keys.reserve(*k);
2408
                // Walk through the expected (pubkey, CHECKSIG[ADD]) pairs.
2409
27
                for (int pos = 2;; pos += 2) {
2410
27
                    if (last - in < pos + 2) return {};
2411
                    // Make sure it's indeed an x-only pubkey and a CHECKSIG[ADD], then parse the key.
2412
26
                    if (in[pos].first != OP_CHECKSIGADD && in[pos].first != OP_CHECKSIG) return {};
2413
26
                    if (in[pos + 1].second.size() != 32) return {};
2414
26
                    auto key = ctx.FromPKBytes(in[pos + 1].second.begin(), in[pos + 1].second.end());
2415
26
                    if (!key) return {};
2416
26
                    keys.push_back(std::move(*key));
2417
                    // Make sure early we don't parse an arbitrary large expression.
2418
26
                    if (keys.size() > MAX_PUBKEYS_PER_MULTI_A) return {};
2419
                    // OP_CHECKSIG means it was the last one to parse.
2420
26
                    if (in[pos].first == OP_CHECKSIG) break;
2421
26
                }
2422
3
                if (keys.size() < (size_t)*k) return {};
2423
3
                in += 2 + keys.size() * 2;
2424
3
                std::reverse(keys.begin(), keys.end());
2425
3
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), *k);
2426
3
                break;
2427
3
            }
2428
            /** In the following wrappers, we only need to push SINGLE_BKV_EXPR rather
2429
             * than BKV_EXPR, because and_v commutes with these wrappers. For example,
2430
             * c:and_v(X,Y) produces the same script as and_v(X,c:Y). */
2431
            // c: wrapper
2432
3.14k
            if (in[0].first == OP_CHECKSIG) {
2433
465
                ++in;
2434
465
                to_parse.emplace_back(DecodeContext::CHECK, -1, -1);
2435
465
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2436
465
                break;
2437
465
            }
2438
            // v: wrapper
2439
2.68k
            if (in[0].first == OP_VERIFY) {
2440
81
                ++in;
2441
81
                to_parse.emplace_back(DecodeContext::VERIFY, -1, -1);
2442
81
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2443
81
                break;
2444
81
            }
2445
            // n: wrapper
2446
2.60k
            if (in[0].first == OP_0NOTEQUAL) {
2447
15
                ++in;
2448
15
                to_parse.emplace_back(DecodeContext::ZERO_NOTEQUAL, -1, -1);
2449
15
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2450
15
                break;
2451
15
            }
2452
            // Thresh
2453
2.58k
            if (last - in >= 3 && in[0].first == OP_EQUAL && (num = ParseScriptNumber(in[1]))) {
2454
16
                if (*num < 1) return {};
2455
16
                in += 2;
2456
16
                to_parse.emplace_back(DecodeContext::THRESH_W, 0, *num);
2457
16
                break;
2458
16
            }
2459
            // OP_ENDIF can be WRAP_J, WRAP_D, ANDOR, OR_C, OR_D, or OR_I
2460
2.56k
            if (in[0].first == OP_ENDIF) {
2461
142
                ++in;
2462
142
                to_parse.emplace_back(DecodeContext::ENDIF, -1, -1);
2463
142
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2464
142
                break;
2465
142
            }
2466
            /** In and_b and or_b nodes, we only look for SINGLE_BKV_EXPR, because
2467
             * or_b(and_v(X,Y),Z) has script [X] [Y] [Z] OP_BOOLOR, the same as
2468
             * and_v(X,or_b(Y,Z)). In this example, the former of these is invalid as
2469
             * miniscript, while the latter is valid. So we leave the and_v "outside"
2470
             * while decoding. */
2471
            // and_b
2472
2.42k
            if (in[0].first == OP_BOOLAND) {
2473
2.41k
                ++in;
2474
2.41k
                to_parse.emplace_back(DecodeContext::AND_B, -1, -1);
2475
2.41k
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2476
2.41k
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2477
2.41k
                break;
2478
2.41k
            }
2479
            // or_b
2480
9
            if (in[0].first == OP_BOOLOR) {
2481
8
                ++in;
2482
8
                to_parse.emplace_back(DecodeContext::OR_B, -1, -1);
2483
8
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2484
8
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2485
8
                break;
2486
8
            }
2487
            // Unrecognised expression
2488
1
            return {};
2489
9
        }
2490
2.90k
        case DecodeContext::BKV_EXPR: {
2491
2.90k
            to_parse.emplace_back(DecodeContext::MAYBE_AND_V, -1, -1);
2492
2.90k
            to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2493
2.90k
            break;
2494
9
        }
2495
2.45k
        case DecodeContext::W_EXPR: {
2496
            // a: wrapper
2497
2.45k
            if (in >= last) return {};
2498
2.45k
            if (in[0].first == OP_FROMALTSTACK) {
2499
2.44k
                ++in;
2500
2.44k
                to_parse.emplace_back(DecodeContext::ALT, -1, -1);
2501
2.44k
            } else {
2502
10
                to_parse.emplace_back(DecodeContext::SWAP, -1, -1);
2503
10
            }
2504
2.45k
            to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2505
2.45k
            break;
2506
2.45k
        }
2507
2.89k
        case DecodeContext::MAYBE_AND_V: {
2508
            // If we reach a potential AND_V top-level, check if the next part of the script could be another AND_V child
2509
            // These op-codes cannot end any well-formed miniscript so cannot be used in an and_v node.
2510
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) {
2511
67
                to_parse.emplace_back(DecodeContext::AND_V, -1, -1);
2512
                // BKV_EXPR can contain more AND_V nodes
2513
67
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2514
67
            }
2515
2.89k
            break;
2516
2.45k
        }
2517
10
        case DecodeContext::SWAP: {
2518
10
            if (in >= last || in[0].first != OP_SWAP || constructed.empty()) return {};
2519
10
            ++in;
2520
10
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S, Vector(std::move(constructed.back()))};
2521
10
            break;
2522
10
        }
2523
2.44k
        case DecodeContext::ALT: {
2524
2.44k
            if (in >= last || in[0].first != OP_TOALTSTACK || constructed.empty()) return {};
2525
2.44k
            ++in;
2526
2.44k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A, Vector(std::move(constructed.back()))};
2527
2.44k
            break;
2528
2.44k
        }
2529
464
        case DecodeContext::CHECK: {
2530
464
            if (constructed.empty()) return {};
2531
464
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(std::move(constructed.back()))};
2532
464
            break;
2533
464
        }
2534
5
        case DecodeContext::DUP_IF: {
2535
5
            if (constructed.empty()) return {};
2536
5
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D, Vector(std::move(constructed.back()))};
2537
5
            break;
2538
5
        }
2539
81
        case DecodeContext::VERIFY: {
2540
81
            if (constructed.empty()) return {};
2541
81
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V, Vector(std::move(constructed.back()))};
2542
81
            break;
2543
81
        }
2544
8
        case DecodeContext::NON_ZERO: {
2545
8
            if (constructed.empty()) return {};
2546
8
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J, Vector(std::move(constructed.back()))};
2547
8
            break;
2548
8
        }
2549
15
        case DecodeContext::ZERO_NOTEQUAL: {
2550
15
            if (constructed.empty()) return {};
2551
15
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N, Vector(std::move(constructed.back()))};
2552
15
            break;
2553
15
        }
2554
66
        case DecodeContext::AND_V: {
2555
66
            if (constructed.size() < 2) return {};
2556
66
            BuildBack(ctx.MsContext(), Fragment::AND_V, constructed, /*reverse=*/true);
2557
66
            break;
2558
66
        }
2559
2.41k
        case DecodeContext::AND_B: {
2560
2.41k
            if (constructed.size() < 2) return {};
2561
2.41k
            BuildBack(ctx.MsContext(), Fragment::AND_B, constructed, /*reverse=*/true);
2562
2.41k
            break;
2563
2.41k
        }
2564
8
        case DecodeContext::OR_B: {
2565
8
            if (constructed.size() < 2) return {};
2566
8
            BuildBack(ctx.MsContext(), Fragment::OR_B, constructed, /*reverse=*/true);
2567
8
            break;
2568
8
        }
2569
6
        case DecodeContext::OR_C: {
2570
6
            if (constructed.size() < 2) return {};
2571
6
            BuildBack(ctx.MsContext(), Fragment::OR_C, constructed, /*reverse=*/true);
2572
6
            break;
2573
6
        }
2574
15
        case DecodeContext::OR_D: {
2575
15
            if (constructed.size() < 2) return {};
2576
15
            BuildBack(ctx.MsContext(), Fragment::OR_D, constructed, /*reverse=*/true);
2577
15
            break;
2578
15
        }
2579
29
        case DecodeContext::ANDOR: {
2580
29
            if (constructed.size() < 3) return {};
2581
29
            Node left{std::move(constructed.back())};
2582
29
            constructed.pop_back();
2583
29
            Node right{std::move(constructed.back())};
2584
29
            constructed.pop_back();
2585
29
            Node mid{std::move(constructed.back())};
2586
29
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR, Vector(std::move(left), std::move(mid), std::move(right))};
2587
29
            break;
2588
29
        }
2589
46
        case DecodeContext::THRESH_W: {
2590
46
            if (in >= last) return {};
2591
46
            if (in[0].first == OP_ADD) {
2592
30
                ++in;
2593
30
                to_parse.emplace_back(DecodeContext::THRESH_W, n+1, k);
2594
30
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2595
30
            } else {
2596
16
                to_parse.emplace_back(DecodeContext::THRESH_E, n+1, k);
2597
                // All children of thresh have type modifier d, so cannot be and_v
2598
16
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2599
16
            }
2600
46
            break;
2601
46
        }
2602
16
        case DecodeContext::THRESH_E: {
2603
16
            if (k < 1 || k > n || constructed.size() < static_cast<size_t>(n)) return {};
2604
16
            std::vector<Node<Key>> subs;
2605
62
            for (int i = 0; i < n; ++i) {
2606
46
                Node sub{std::move(constructed.back())};
2607
46
                constructed.pop_back();
2608
46
                subs.push_back(std::move(sub));
2609
46
            }
2610
16
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs), k);
2611
16
            break;
2612
16
        }
2613
142
        case DecodeContext::ENDIF: {
2614
142
            if (in >= last) return {};
2615
2616
            // could be andor or or_i
2617
142
            if (in[0].first == OP_ELSE) {
2618
108
                ++in;
2619
108
                to_parse.emplace_back(DecodeContext::ENDIF_ELSE, -1, -1);
2620
108
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2621
108
            }
2622
            // could be j: or d: wrapper
2623
34
            else if (in[0].first == OP_IF) {
2624
13
                if (last - in >= 2 && in[1].first == OP_DUP) {
2625
5
                    in += 2;
2626
5
                    to_parse.emplace_back(DecodeContext::DUP_IF, -1, -1);
2627
8
                } else if (last - in >= 3 && in[1].first == OP_0NOTEQUAL && in[2].first == OP_SIZE) {
2628
8
                    in += 3;
2629
8
                    to_parse.emplace_back(DecodeContext::NON_ZERO, -1, -1);
2630
8
                }
2631
0
                else {
2632
0
                    return {};
2633
0
                }
2634
            // could be or_c or or_d
2635
21
            } else if (in[0].first == OP_NOTIF) {
2636
21
                ++in;
2637
21
                to_parse.emplace_back(DecodeContext::ENDIF_NOTIF, -1, -1);
2638
21
            }
2639
0
            else {
2640
0
                return {};
2641
0
            }
2642
142
            break;
2643
142
        }
2644
142
        case DecodeContext::ENDIF_NOTIF: {
2645
21
            if (in >= last) return {};
2646
21
            if (in[0].first == OP_IFDUP) {
2647
15
                ++in;
2648
15
                to_parse.emplace_back(DecodeContext::OR_D, -1, -1);
2649
15
            } else {
2650
6
                to_parse.emplace_back(DecodeContext::OR_C, -1, -1);
2651
6
            }
2652
            // or_c and or_d both require X to have type modifier d so, can't contain and_v
2653
21
            to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2654
21
            break;
2655
21
        }
2656
108
        case DecodeContext::ENDIF_ELSE: {
2657
108
            if (in >= last) return {};
2658
108
            if (in[0].first == OP_IF) {
2659
79
                ++in;
2660
79
                BuildBack(ctx.MsContext(), Fragment::OR_I, constructed, /*reverse=*/true);
2661
79
            } else if (in[0].first == OP_NOTIF) {
2662
29
                ++in;
2663
29
                to_parse.emplace_back(DecodeContext::ANDOR, -1, -1);
2664
                // andor requires X to have type modifier d, so it can't be and_v
2665
29
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2666
29
            } else {
2667
0
                return {};
2668
0
            }
2669
108
            break;
2670
108
        }
2671
20.1k
        }
2672
20.1k
    }
2673
125
    if (constructed.size() != 1) return {};
2674
125
    Node tl_node{std::move(constructed.front())};
2675
125
    tl_node.DuplicateKeyCheck(ctx);
2676
    // Note that due to how ComputeType works (only assign the type to the node if the
2677
    // subs' types are valid) this would fail if any node of tree is badly typed.
2678
125
    if (!tl_node.IsValidTopLevel()) return {};
2679
125
    return tl_node;
2680
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
2297
624
{
2298
    // The two integers are used to hold state for thresh()
2299
624
    std::vector<std::tuple<DecodeContext, int64_t, int64_t>> to_parse;
2300
624
    std::vector<Node<Key>> constructed;
2301
2302
    // This is the top level, so we assume the type is B
2303
    // (in particular, disallowing top level W expressions)
2304
624
    to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2305
2306
1.33M
    while (!to_parse.empty()) {
2307
        // Exit early if the Miniscript is not going to be valid.
2308
1.33M
        if (!constructed.empty() && !constructed.back().IsValid()) return {};
2309
2310
        // Get the current context we are decoding within
2311
1.33M
        auto [cur_context, n, k] = to_parse.back();
2312
1.33M
        to_parse.pop_back();
2313
2314
1.33M
        switch(cur_context) {
2315
663k
        case DecodeContext::SINGLE_BKV_EXPR: {
2316
663k
            if (in >= last) return {};
2317
2318
            // Constants
2319
663k
            if (in[0].first == OP_1) {
2320
3
                ++in;
2321
3
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1);
2322
3
                break;
2323
3
            }
2324
663k
            if (in[0].first == OP_0) {
2325
193
                ++in;
2326
193
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
2327
193
                break;
2328
193
            }
2329
            // Public keys
2330
663k
            if (in[0].second.size() == 33 || in[0].second.size() == 32) {
2331
937
                auto key = ctx.FromPKBytes(in[0].second.begin(), in[0].second.end());
2332
937
                if (!key) return {};
2333
935
                ++in;
2334
935
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_K, Vector(std::move(*key)));
2335
935
                break;
2336
937
            }
2337
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) {
2338
312
                auto key = ctx.FromPKHBytes(in[2].second.begin(), in[2].second.end());
2339
312
                if (!key) return {};
2340
310
                in += 5;
2341
310
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_H, Vector(std::move(*key)));
2342
310
                break;
2343
312
            }
2344
            // Time locks
2345
662k
            std::optional<int64_t> num;
2346
662k
            if (last - in >= 2 && in[0].first == OP_CHECKSEQUENCEVERIFY && (num = ParseScriptNumber(in[1]))) {
2347
192
                in += 2;
2348
192
                if (*num < 1 || *num > 0x7FFFFFFFL) return {};
2349
192
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num);
2350
192
                break;
2351
192
            }
2352
662k
            if (last - in >= 2 && in[0].first == OP_CHECKLOCKTIMEVERIFY && (num = ParseScriptNumber(in[1]))) {
2353
232
                in += 2;
2354
232
                if (num < 1 || num > 0x7FFFFFFFL) return {};
2355
232
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num);
2356
232
                break;
2357
232
            }
2358
            // Hashes
2359
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) {
2360
155
                if (in[2].first == OP_SHA256 && in[1].second.size() == 32) {
2361
28
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, in[1].second);
2362
28
                    in += 7;
2363
28
                    break;
2364
127
                } else if (in[2].first == OP_RIPEMD160 && in[1].second.size() == 20) {
2365
36
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::RIPEMD160, in[1].second);
2366
36
                    in += 7;
2367
36
                    break;
2368
91
                } else if (in[2].first == OP_HASH256 && in[1].second.size() == 32) {
2369
48
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, in[1].second);
2370
48
                    in += 7;
2371
48
                    break;
2372
48
                } else if (in[2].first == OP_HASH160 && in[1].second.size() == 20) {
2373
43
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, in[1].second);
2374
43
                    in += 7;
2375
43
                    break;
2376
43
                }
2377
155
            }
2378
            // Multi
2379
661k
            if (last - in >= 3 && in[0].first == OP_CHECKMULTISIG) {
2380
94
                if (IsTapscript(ctx.MsContext())) return {};
2381
94
                std::vector<Key> keys;
2382
94
                const auto n = ParseScriptNumber(in[1]);
2383
94
                if (!n || last - in < 3 + *n) return {};
2384
94
                if (*n < 1 || *n > 20) return {};
2385
328
                for (int i = 0; i < *n; ++i) {
2386
234
                    if (in[2 + i].second.size() != 33) return {};
2387
234
                    auto key = ctx.FromPKBytes(in[2 + i].second.begin(), in[2 + i].second.end());
2388
234
                    if (!key) return {};
2389
234
                    keys.push_back(std::move(*key));
2390
234
                }
2391
94
                const auto k = ParseScriptNumber(in[2 + *n]);
2392
94
                if (!k || *k < 1 || *k > *n) return {};
2393
94
                in += 3 + *n;
2394
94
                std::reverse(keys.begin(), keys.end());
2395
94
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), *k);
2396
94
                break;
2397
94
            }
2398
            // Tapscript's equivalent of multi
2399
661k
            if (last - in >= 4 && in[0].first == OP_NUMEQUAL) {
2400
4
                if (!IsTapscript(ctx.MsContext())) return {};
2401
                // The necessary threshold of signatures.
2402
4
                const auto k = ParseScriptNumber(in[1]);
2403
4
                if (!k) return {};
2404
4
                if (*k < 1 || *k > MAX_PUBKEYS_PER_MULTI_A) return {};
2405
4
                if (last - in < 2 + *k * 2) return {};
2406
4
                std::vector<Key> keys;
2407
4
                keys.reserve(*k);
2408
                // Walk through the expected (pubkey, CHECKSIG[ADD]) pairs.
2409
8
                for (int pos = 2;; pos += 2) {
2410
8
                    if (last - in < pos + 2) return {};
2411
                    // Make sure it's indeed an x-only pubkey and a CHECKSIG[ADD], then parse the key.
2412
8
                    if (in[pos].first != OP_CHECKSIGADD && in[pos].first != OP_CHECKSIG) return {};
2413
8
                    if (in[pos + 1].second.size() != 32) return {};
2414
8
                    auto key = ctx.FromPKBytes(in[pos + 1].second.begin(), in[pos + 1].second.end());
2415
8
                    if (!key) return {};
2416
8
                    keys.push_back(std::move(*key));
2417
                    // Make sure early we don't parse an arbitrary large expression.
2418
8
                    if (keys.size() > MAX_PUBKEYS_PER_MULTI_A) return {};
2419
                    // OP_CHECKSIG means it was the last one to parse.
2420
8
                    if (in[pos].first == OP_CHECKSIG) break;
2421
8
                }
2422
4
                if (keys.size() < (size_t)*k) return {};
2423
4
                in += 2 + keys.size() * 2;
2424
4
                std::reverse(keys.begin(), keys.end());
2425
4
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), *k);
2426
4
                break;
2427
4
            }
2428
            /** In the following wrappers, we only need to push SINGLE_BKV_EXPR rather
2429
             * than BKV_EXPR, because and_v commutes with these wrappers. For example,
2430
             * c:and_v(X,Y) produces the same script as and_v(X,c:Y). */
2431
            // c: wrapper
2432
661k
            if (in[0].first == OP_CHECKSIG) {
2433
1.23k
                ++in;
2434
1.23k
                to_parse.emplace_back(DecodeContext::CHECK, -1, -1);
2435
1.23k
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2436
1.23k
                break;
2437
1.23k
            }
2438
            // v: wrapper
2439
660k
            if (in[0].first == OP_VERIFY) {
2440
498
                ++in;
2441
498
                to_parse.emplace_back(DecodeContext::VERIFY, -1, -1);
2442
498
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2443
498
                break;
2444
498
            }
2445
            // n: wrapper
2446
659k
            if (in[0].first == OP_0NOTEQUAL) {
2447
659k
                ++in;
2448
659k
                to_parse.emplace_back(DecodeContext::ZERO_NOTEQUAL, -1, -1);
2449
659k
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2450
659k
                break;
2451
659k
            }
2452
            // Thresh
2453
783
            if (last - in >= 3 && in[0].first == OP_EQUAL && (num = ParseScriptNumber(in[1]))) {
2454
178
                if (*num < 1) return {};
2455
178
                in += 2;
2456
178
                to_parse.emplace_back(DecodeContext::THRESH_W, 0, *num);
2457
178
                break;
2458
178
            }
2459
            // OP_ENDIF can be WRAP_J, WRAP_D, ANDOR, OR_C, OR_D, or OR_I
2460
605
            if (in[0].first == OP_ENDIF) {
2461
391
                ++in;
2462
391
                to_parse.emplace_back(DecodeContext::ENDIF, -1, -1);
2463
391
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2464
391
                break;
2465
391
            }
2466
            /** In and_b and or_b nodes, we only look for SINGLE_BKV_EXPR, because
2467
             * or_b(and_v(X,Y),Z) has script [X] [Y] [Z] OP_BOOLOR, the same as
2468
             * and_v(X,or_b(Y,Z)). In this example, the former of these is invalid as
2469
             * miniscript, while the latter is valid. So we leave the and_v "outside"
2470
             * while decoding. */
2471
            // and_b
2472
214
            if (in[0].first == OP_BOOLAND) {
2473
184
                ++in;
2474
184
                to_parse.emplace_back(DecodeContext::AND_B, -1, -1);
2475
184
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2476
184
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2477
184
                break;
2478
184
            }
2479
            // or_b
2480
30
            if (in[0].first == OP_BOOLOR) {
2481
22
                ++in;
2482
22
                to_parse.emplace_back(DecodeContext::OR_B, -1, -1);
2483
22
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2484
22
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2485
22
                break;
2486
22
            }
2487
            // Unrecognised expression
2488
8
            return {};
2489
30
        }
2490
2.37k
        case DecodeContext::BKV_EXPR: {
2491
2.37k
            to_parse.emplace_back(DecodeContext::MAYBE_AND_V, -1, -1);
2492
2.37k
            to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2493
2.37k
            break;
2494
30
        }
2495
634
        case DecodeContext::W_EXPR: {
2496
            // a: wrapper
2497
634
            if (in >= last) return {};
2498
634
            if (in[0].first == OP_FROMALTSTACK) {
2499
350
                ++in;
2500
350
                to_parse.emplace_back(DecodeContext::ALT, -1, -1);
2501
350
            } else {
2502
284
                to_parse.emplace_back(DecodeContext::SWAP, -1, -1);
2503
284
            }
2504
634
            to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2505
634
            break;
2506
634
        }
2507
2.36k
        case DecodeContext::MAYBE_AND_V: {
2508
            // If we reach a potential AND_V top-level, check if the next part of the script could be another AND_V child
2509
            // These op-codes cannot end any well-formed miniscript so cannot be used in an and_v node.
2510
2.36k
            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) {
2511
449
                to_parse.emplace_back(DecodeContext::AND_V, -1, -1);
2512
                // BKV_EXPR can contain more AND_V nodes
2513
449
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2514
449
            }
2515
2.36k
            break;
2516
634
        }
2517
284
        case DecodeContext::SWAP: {
2518
284
            if (in >= last || in[0].first != OP_SWAP || constructed.empty()) return {};
2519
284
            ++in;
2520
284
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S, Vector(std::move(constructed.back()))};
2521
284
            break;
2522
284
        }
2523
350
        case DecodeContext::ALT: {
2524
350
            if (in >= last || in[0].first != OP_TOALTSTACK || constructed.empty()) return {};
2525
350
            ++in;
2526
350
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A, Vector(std::move(constructed.back()))};
2527
350
            break;
2528
350
        }
2529
1.23k
        case DecodeContext::CHECK: {
2530
1.23k
            if (constructed.empty()) return {};
2531
1.23k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(std::move(constructed.back()))};
2532
1.23k
            break;
2533
1.23k
        }
2534
52
        case DecodeContext::DUP_IF: {
2535
52
            if (constructed.empty()) return {};
2536
52
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D, Vector(std::move(constructed.back()))};
2537
52
            break;
2538
52
        }
2539
498
        case DecodeContext::VERIFY: {
2540
498
            if (constructed.empty()) return {};
2541
498
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V, Vector(std::move(constructed.back()))};
2542
498
            break;
2543
498
        }
2544
0
        case DecodeContext::NON_ZERO: {
2545
0
            if (constructed.empty()) return {};
2546
0
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J, Vector(std::move(constructed.back()))};
2547
0
            break;
2548
0
        }
2549
659k
        case DecodeContext::ZERO_NOTEQUAL: {
2550
659k
            if (constructed.empty()) return {};
2551
659k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N, Vector(std::move(constructed.back()))};
2552
659k
            break;
2553
659k
        }
2554
447
        case DecodeContext::AND_V: {
2555
447
            if (constructed.size() < 2) return {};
2556
447
            BuildBack(ctx.MsContext(), Fragment::AND_V, constructed, /*reverse=*/true);
2557
447
            break;
2558
447
        }
2559
184
        case DecodeContext::AND_B: {
2560
184
            if (constructed.size() < 2) return {};
2561
184
            BuildBack(ctx.MsContext(), Fragment::AND_B, constructed, /*reverse=*/true);
2562
184
            break;
2563
184
        }
2564
22
        case DecodeContext::OR_B: {
2565
22
            if (constructed.size() < 2) return {};
2566
22
            BuildBack(ctx.MsContext(), Fragment::OR_B, constructed, /*reverse=*/true);
2567
22
            break;
2568
22
        }
2569
18
        case DecodeContext::OR_C: {
2570
18
            if (constructed.size() < 2) return {};
2571
18
            BuildBack(ctx.MsContext(), Fragment::OR_C, constructed, /*reverse=*/true);
2572
18
            break;
2573
18
        }
2574
45
        case DecodeContext::OR_D: {
2575
45
            if (constructed.size() < 2) return {};
2576
45
            BuildBack(ctx.MsContext(), Fragment::OR_D, constructed, /*reverse=*/true);
2577
45
            break;
2578
45
        }
2579
85
        case DecodeContext::ANDOR: {
2580
85
            if (constructed.size() < 3) return {};
2581
85
            Node left{std::move(constructed.back())};
2582
85
            constructed.pop_back();
2583
85
            Node right{std::move(constructed.back())};
2584
85
            constructed.pop_back();
2585
85
            Node mid{std::move(constructed.back())};
2586
85
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR, Vector(std::move(left), std::move(mid), std::move(right))};
2587
85
            break;
2588
85
        }
2589
606
        case DecodeContext::THRESH_W: {
2590
606
            if (in >= last) return {};
2591
606
            if (in[0].first == OP_ADD) {
2592
428
                ++in;
2593
428
                to_parse.emplace_back(DecodeContext::THRESH_W, n+1, k);
2594
428
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2595
428
            } else {
2596
178
                to_parse.emplace_back(DecodeContext::THRESH_E, n+1, k);
2597
                // All children of thresh have type modifier d, so cannot be and_v
2598
178
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2599
178
            }
2600
606
            break;
2601
606
        }
2602
178
        case DecodeContext::THRESH_E: {
2603
178
            if (k < 1 || k > n || constructed.size() < static_cast<size_t>(n)) return {};
2604
178
            std::vector<Node<Key>> subs;
2605
784
            for (int i = 0; i < n; ++i) {
2606
606
                Node sub{std::move(constructed.back())};
2607
606
                constructed.pop_back();
2608
606
                subs.push_back(std::move(sub));
2609
606
            }
2610
178
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs), k);
2611
178
            break;
2612
178
        }
2613
390
        case DecodeContext::ENDIF: {
2614
390
            if (in >= last) return {};
2615
2616
            // could be andor or or_i
2617
390
            if (in[0].first == OP_ELSE) {
2618
275
                ++in;
2619
275
                to_parse.emplace_back(DecodeContext::ENDIF_ELSE, -1, -1);
2620
275
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2621
275
            }
2622
            // could be j: or d: wrapper
2623
115
            else if (in[0].first == OP_IF) {
2624
52
                if (last - in >= 2 && in[1].first == OP_DUP) {
2625
52
                    in += 2;
2626
52
                    to_parse.emplace_back(DecodeContext::DUP_IF, -1, -1);
2627
52
                } else if (last - in >= 3 && in[1].first == OP_0NOTEQUAL && in[2].first == OP_SIZE) {
2628
0
                    in += 3;
2629
0
                    to_parse.emplace_back(DecodeContext::NON_ZERO, -1, -1);
2630
0
                }
2631
0
                else {
2632
0
                    return {};
2633
0
                }
2634
            // could be or_c or or_d
2635
63
            } else if (in[0].first == OP_NOTIF) {
2636
63
                ++in;
2637
63
                to_parse.emplace_back(DecodeContext::ENDIF_NOTIF, -1, -1);
2638
63
            }
2639
0
            else {
2640
0
                return {};
2641
0
            }
2642
390
            break;
2643
390
        }
2644
390
        case DecodeContext::ENDIF_NOTIF: {
2645
63
            if (in >= last) return {};
2646
63
            if (in[0].first == OP_IFDUP) {
2647
45
                ++in;
2648
45
                to_parse.emplace_back(DecodeContext::OR_D, -1, -1);
2649
45
            } else {
2650
18
                to_parse.emplace_back(DecodeContext::OR_C, -1, -1);
2651
18
            }
2652
            // or_c and or_d both require X to have type modifier d so, can't contain and_v
2653
63
            to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2654
63
            break;
2655
63
        }
2656
275
        case DecodeContext::ENDIF_ELSE: {
2657
275
            if (in >= last) return {};
2658
275
            if (in[0].first == OP_IF) {
2659
190
                ++in;
2660
190
                BuildBack(ctx.MsContext(), Fragment::OR_I, constructed, /*reverse=*/true);
2661
190
            } else if (in[0].first == OP_NOTIF) {
2662
85
                ++in;
2663
85
                to_parse.emplace_back(DecodeContext::ANDOR, -1, -1);
2664
                // andor requires X to have type modifier d, so it can't be and_v
2665
85
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2666
85
            } else {
2667
0
                return {};
2668
0
            }
2669
275
            break;
2670
275
        }
2671
1.33M
        }
2672
1.33M
    }
2673
612
    if (constructed.size() != 1) return {};
2674
612
    Node tl_node{std::move(constructed.front())};
2675
612
    tl_node.DuplicateKeyCheck(ctx);
2676
    // Note that due to how ComputeType works (only assign the type to the node if the
2677
    // subs' types are valid) this would fail if any node of tree is badly typed.
2678
612
    if (!tl_node.IsValidTopLevel()) return {};
2679
611
    return tl_node;
2680
612
}
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
2297
3.05k
{
2298
    // The two integers are used to hold state for thresh()
2299
3.05k
    std::vector<std::tuple<DecodeContext, int64_t, int64_t>> to_parse;
2300
3.05k
    std::vector<Node<Key>> constructed;
2301
2302
    // This is the top level, so we assume the type is B
2303
    // (in particular, disallowing top level W expressions)
2304
3.05k
    to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2305
2306
10.5M
    while (!to_parse.empty()) {
2307
        // Exit early if the Miniscript is not going to be valid.
2308
10.5M
        if (!constructed.empty() && !constructed.back().IsValid()) return {};
2309
2310
        // Get the current context we are decoding within
2311
10.5M
        auto [cur_context, n, k] = to_parse.back();
2312
10.5M
        to_parse.pop_back();
2313
2314
10.5M
        switch(cur_context) {
2315
5.27M
        case DecodeContext::SINGLE_BKV_EXPR: {
2316
5.27M
            if (in >= last) return {};
2317
2318
            // Constants
2319
5.27M
            if (in[0].first == OP_1) {
2320
0
                ++in;
2321
0
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1);
2322
0
                break;
2323
0
            }
2324
5.27M
            if (in[0].first == OP_0) {
2325
0
                ++in;
2326
0
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
2327
0
                break;
2328
0
            }
2329
            // Public keys
2330
5.27M
            if (in[0].second.size() == 33 || in[0].second.size() == 32) {
2331
2.21k
                auto key = ctx.FromPKBytes(in[0].second.begin(), in[0].second.end());
2332
2.21k
                if (!key) return {};
2333
2.21k
                ++in;
2334
2.21k
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_K, Vector(std::move(*key)));
2335
2.21k
                break;
2336
2.21k
            }
2337
5.27M
            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) {
2338
186
                auto key = ctx.FromPKHBytes(in[2].second.begin(), in[2].second.end());
2339
186
                if (!key) return {};
2340
186
                in += 5;
2341
186
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_H, Vector(std::move(*key)));
2342
186
                break;
2343
186
            }
2344
            // Time locks
2345
5.27M
            std::optional<int64_t> num;
2346
5.27M
            if (last - in >= 2 && in[0].first == OP_CHECKSEQUENCEVERIFY && (num = ParseScriptNumber(in[1]))) {
2347
49
                in += 2;
2348
49
                if (*num < 1 || *num > 0x7FFFFFFFL) return {};
2349
49
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num);
2350
49
                break;
2351
49
            }
2352
5.27M
            if (last - in >= 2 && in[0].first == OP_CHECKLOCKTIMEVERIFY && (num = ParseScriptNumber(in[1]))) {
2353
380
                in += 2;
2354
380
                if (num < 1 || num > 0x7FFFFFFFL) return {};
2355
380
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num);
2356
380
                break;
2357
380
            }
2358
            // Hashes
2359
5.27M
            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) {
2360
12
                if (in[2].first == OP_SHA256 && in[1].second.size() == 32) {
2361
0
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, in[1].second);
2362
0
                    in += 7;
2363
0
                    break;
2364
12
                } else if (in[2].first == OP_RIPEMD160 && in[1].second.size() == 20) {
2365
0
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::RIPEMD160, in[1].second);
2366
0
                    in += 7;
2367
0
                    break;
2368
12
                } else if (in[2].first == OP_HASH256 && in[1].second.size() == 32) {
2369
12
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, in[1].second);
2370
12
                    in += 7;
2371
12
                    break;
2372
12
                } else if (in[2].first == OP_HASH160 && in[1].second.size() == 20) {
2373
0
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, in[1].second);
2374
0
                    in += 7;
2375
0
                    break;
2376
0
                }
2377
12
            }
2378
            // Multi
2379
5.27M
            if (last - in >= 3 && in[0].first == OP_CHECKMULTISIG) {
2380
0
                if (IsTapscript(ctx.MsContext())) return {};
2381
0
                std::vector<Key> keys;
2382
0
                const auto n = ParseScriptNumber(in[1]);
2383
0
                if (!n || last - in < 3 + *n) return {};
2384
0
                if (*n < 1 || *n > 20) return {};
2385
0
                for (int i = 0; i < *n; ++i) {
2386
0
                    if (in[2 + i].second.size() != 33) return {};
2387
0
                    auto key = ctx.FromPKBytes(in[2 + i].second.begin(), in[2 + i].second.end());
2388
0
                    if (!key) return {};
2389
0
                    keys.push_back(std::move(*key));
2390
0
                }
2391
0
                const auto k = ParseScriptNumber(in[2 + *n]);
2392
0
                if (!k || *k < 1 || *k > *n) return {};
2393
0
                in += 3 + *n;
2394
0
                std::reverse(keys.begin(), keys.end());
2395
0
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), *k);
2396
0
                break;
2397
0
            }
2398
            // Tapscript's equivalent of multi
2399
5.27M
            if (last - in >= 4 && in[0].first == OP_NUMEQUAL) {
2400
771
                if (!IsTapscript(ctx.MsContext())) return {};
2401
                // The necessary threshold of signatures.
2402
771
                const auto k = ParseScriptNumber(in[1]);
2403
771
                if (!k) return {};
2404
771
                if (*k < 1 || *k > MAX_PUBKEYS_PER_MULTI_A) return {};
2405
771
                if (last - in < 2 + *k * 2) return {};
2406
771
                std::vector<Key> keys;
2407
771
                keys.reserve(*k);
2408
                // Walk through the expected (pubkey, CHECKSIG[ADD]) pairs.
2409
90.5k
                for (int pos = 2;; pos += 2) {
2410
90.5k
                    if (last - in < pos + 2) return {};
2411
                    // Make sure it's indeed an x-only pubkey and a CHECKSIG[ADD], then parse the key.
2412
90.5k
                    if (in[pos].first != OP_CHECKSIGADD && in[pos].first != OP_CHECKSIG) return {};
2413
90.5k
                    if (in[pos + 1].second.size() != 32) return {};
2414
90.5k
                    auto key = ctx.FromPKBytes(in[pos + 1].second.begin(), in[pos + 1].second.end());
2415
90.5k
                    if (!key) return {};
2416
90.5k
                    keys.push_back(std::move(*key));
2417
                    // Make sure early we don't parse an arbitrary large expression.
2418
90.5k
                    if (keys.size() > MAX_PUBKEYS_PER_MULTI_A) return {};
2419
                    // OP_CHECKSIG means it was the last one to parse.
2420
90.5k
                    if (in[pos].first == OP_CHECKSIG) break;
2421
90.5k
                }
2422
771
                if (keys.size() < (size_t)*k) return {};
2423
771
                in += 2 + keys.size() * 2;
2424
771
                std::reverse(keys.begin(), keys.end());
2425
771
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), *k);
2426
771
                break;
2427
771
            }
2428
            /** In the following wrappers, we only need to push SINGLE_BKV_EXPR rather
2429
             * than BKV_EXPR, because and_v commutes with these wrappers. For example,
2430
             * c:and_v(X,Y) produces the same script as and_v(X,c:Y). */
2431
            // c: wrapper
2432
5.27M
            if (in[0].first == OP_CHECKSIG) {
2433
2.40k
                ++in;
2434
2.40k
                to_parse.emplace_back(DecodeContext::CHECK, -1, -1);
2435
2.40k
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2436
2.40k
                break;
2437
2.40k
            }
2438
            // v: wrapper
2439
5.27M
            if (in[0].first == OP_VERIFY) {
2440
479
                ++in;
2441
479
                to_parse.emplace_back(DecodeContext::VERIFY, -1, -1);
2442
479
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2443
479
                break;
2444
479
            }
2445
            // n: wrapper
2446
5.27M
            if (in[0].first == OP_0NOTEQUAL) {
2447
5.27M
                ++in;
2448
5.27M
                to_parse.emplace_back(DecodeContext::ZERO_NOTEQUAL, -1, -1);
2449
5.27M
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2450
5.27M
                break;
2451
5.27M
            }
2452
            // Thresh
2453
72
            if (last - in >= 3 && in[0].first == OP_EQUAL && (num = ParseScriptNumber(in[1]))) {
2454
18
                if (*num < 1) return {};
2455
18
                in += 2;
2456
18
                to_parse.emplace_back(DecodeContext::THRESH_W, 0, *num);
2457
18
                break;
2458
18
            }
2459
            // OP_ENDIF can be WRAP_J, WRAP_D, ANDOR, OR_C, OR_D, or OR_I
2460
54
            if (in[0].first == OP_ENDIF) {
2461
6
                ++in;
2462
6
                to_parse.emplace_back(DecodeContext::ENDIF, -1, -1);
2463
6
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2464
6
                break;
2465
6
            }
2466
            /** In and_b and or_b nodes, we only look for SINGLE_BKV_EXPR, because
2467
             * or_b(and_v(X,Y),Z) has script [X] [Y] [Z] OP_BOOLOR, the same as
2468
             * and_v(X,or_b(Y,Z)). In this example, the former of these is invalid as
2469
             * miniscript, while the latter is valid. So we leave the and_v "outside"
2470
             * while decoding. */
2471
            // and_b
2472
48
            if (in[0].first == OP_BOOLAND) {
2473
48
                ++in;
2474
48
                to_parse.emplace_back(DecodeContext::AND_B, -1, -1);
2475
48
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2476
48
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2477
48
                break;
2478
48
            }
2479
            // or_b
2480
0
            if (in[0].first == OP_BOOLOR) {
2481
0
                ++in;
2482
0
                to_parse.emplace_back(DecodeContext::OR_B, -1, -1);
2483
0
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2484
0
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2485
0
                break;
2486
0
            }
2487
            // Unrecognised expression
2488
0
            return {};
2489
0
        }
2490
3.61k
        case DecodeContext::BKV_EXPR: {
2491
3.61k
            to_parse.emplace_back(DecodeContext::MAYBE_AND_V, -1, -1);
2492
3.61k
            to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2493
3.61k
            break;
2494
0
        }
2495
84
        case DecodeContext::W_EXPR: {
2496
            // a: wrapper
2497
84
            if (in >= last) return {};
2498
84
            if (in[0].first == OP_FROMALTSTACK) {
2499
66
                ++in;
2500
66
                to_parse.emplace_back(DecodeContext::ALT, -1, -1);
2501
66
            } else {
2502
18
                to_parse.emplace_back(DecodeContext::SWAP, -1, -1);
2503
18
            }
2504
84
            to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2505
84
            break;
2506
84
        }
2507
3.61k
        case DecodeContext::MAYBE_AND_V: {
2508
            // If we reach a potential AND_V top-level, check if the next part of the script could be another AND_V child
2509
            // These op-codes cannot end any well-formed miniscript so cannot be used in an and_v node.
2510
3.61k
            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) {
2511
473
                to_parse.emplace_back(DecodeContext::AND_V, -1, -1);
2512
                // BKV_EXPR can contain more AND_V nodes
2513
473
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2514
473
            }
2515
3.61k
            break;
2516
84
        }
2517
18
        case DecodeContext::SWAP: {
2518
18
            if (in >= last || in[0].first != OP_SWAP || constructed.empty()) return {};
2519
18
            ++in;
2520
18
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S, Vector(std::move(constructed.back()))};
2521
18
            break;
2522
18
        }
2523
66
        case DecodeContext::ALT: {
2524
66
            if (in >= last || in[0].first != OP_TOALTSTACK || constructed.empty()) return {};
2525
66
            ++in;
2526
66
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A, Vector(std::move(constructed.back()))};
2527
66
            break;
2528
66
        }
2529
2.40k
        case DecodeContext::CHECK: {
2530
2.40k
            if (constructed.empty()) return {};
2531
2.40k
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(std::move(constructed.back()))};
2532
2.40k
            break;
2533
2.40k
        }
2534
6
        case DecodeContext::DUP_IF: {
2535
6
            if (constructed.empty()) return {};
2536
6
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D, Vector(std::move(constructed.back()))};
2537
6
            break;
2538
6
        }
2539
479
        case DecodeContext::VERIFY: {
2540
479
            if (constructed.empty()) return {};
2541
479
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V, Vector(std::move(constructed.back()))};
2542
479
            break;
2543
479
        }
2544
0
        case DecodeContext::NON_ZERO: {
2545
0
            if (constructed.empty()) return {};
2546
0
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J, Vector(std::move(constructed.back()))};
2547
0
            break;
2548
0
        }
2549
5.27M
        case DecodeContext::ZERO_NOTEQUAL: {
2550
5.27M
            if (constructed.empty()) return {};
2551
5.27M
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N, Vector(std::move(constructed.back()))};
2552
5.27M
            break;
2553
5.27M
        }
2554
473
        case DecodeContext::AND_V: {
2555
473
            if (constructed.size() < 2) return {};
2556
473
            BuildBack(ctx.MsContext(), Fragment::AND_V, constructed, /*reverse=*/true);
2557
473
            break;
2558
473
        }
2559
48
        case DecodeContext::AND_B: {
2560
48
            if (constructed.size() < 2) return {};
2561
48
            BuildBack(ctx.MsContext(), Fragment::AND_B, constructed, /*reverse=*/true);
2562
48
            break;
2563
48
        }
2564
0
        case DecodeContext::OR_B: {
2565
0
            if (constructed.size() < 2) return {};
2566
0
            BuildBack(ctx.MsContext(), Fragment::OR_B, constructed, /*reverse=*/true);
2567
0
            break;
2568
0
        }
2569
0
        case DecodeContext::OR_C: {
2570
0
            if (constructed.size() < 2) return {};
2571
0
            BuildBack(ctx.MsContext(), Fragment::OR_C, constructed, /*reverse=*/true);
2572
0
            break;
2573
0
        }
2574
0
        case DecodeContext::OR_D: {
2575
0
            if (constructed.size() < 2) return {};
2576
0
            BuildBack(ctx.MsContext(), Fragment::OR_D, constructed, /*reverse=*/true);
2577
0
            break;
2578
0
        }
2579
0
        case DecodeContext::ANDOR: {
2580
0
            if (constructed.size() < 3) return {};
2581
0
            Node left{std::move(constructed.back())};
2582
0
            constructed.pop_back();
2583
0
            Node right{std::move(constructed.back())};
2584
0
            constructed.pop_back();
2585
0
            Node mid{std::move(constructed.back())};
2586
0
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR, Vector(std::move(left), std::move(mid), std::move(right))};
2587
0
            break;
2588
0
        }
2589
54
        case DecodeContext::THRESH_W: {
2590
54
            if (in >= last) return {};
2591
54
            if (in[0].first == OP_ADD) {
2592
36
                ++in;
2593
36
                to_parse.emplace_back(DecodeContext::THRESH_W, n+1, k);
2594
36
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2595
36
            } else {
2596
18
                to_parse.emplace_back(DecodeContext::THRESH_E, n+1, k);
2597
                // All children of thresh have type modifier d, so cannot be and_v
2598
18
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2599
18
            }
2600
54
            break;
2601
54
        }
2602
18
        case DecodeContext::THRESH_E: {
2603
18
            if (k < 1 || k > n || constructed.size() < static_cast<size_t>(n)) return {};
2604
18
            std::vector<Node<Key>> subs;
2605
72
            for (int i = 0; i < n; ++i) {
2606
54
                Node sub{std::move(constructed.back())};
2607
54
                constructed.pop_back();
2608
54
                subs.push_back(std::move(sub));
2609
54
            }
2610
18
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs), k);
2611
18
            break;
2612
18
        }
2613
6
        case DecodeContext::ENDIF: {
2614
6
            if (in >= last) return {};
2615
2616
            // could be andor or or_i
2617
6
            if (in[0].first == OP_ELSE) {
2618
0
                ++in;
2619
0
                to_parse.emplace_back(DecodeContext::ENDIF_ELSE, -1, -1);
2620
0
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2621
0
            }
2622
            // could be j: or d: wrapper
2623
6
            else if (in[0].first == OP_IF) {
2624
6
                if (last - in >= 2 && in[1].first == OP_DUP) {
2625
6
                    in += 2;
2626
6
                    to_parse.emplace_back(DecodeContext::DUP_IF, -1, -1);
2627
6
                } else if (last - in >= 3 && in[1].first == OP_0NOTEQUAL && in[2].first == OP_SIZE) {
2628
0
                    in += 3;
2629
0
                    to_parse.emplace_back(DecodeContext::NON_ZERO, -1, -1);
2630
0
                }
2631
0
                else {
2632
0
                    return {};
2633
0
                }
2634
            // could be or_c or or_d
2635
6
            } else if (in[0].first == OP_NOTIF) {
2636
0
                ++in;
2637
0
                to_parse.emplace_back(DecodeContext::ENDIF_NOTIF, -1, -1);
2638
0
            }
2639
0
            else {
2640
0
                return {};
2641
0
            }
2642
6
            break;
2643
6
        }
2644
6
        case DecodeContext::ENDIF_NOTIF: {
2645
0
            if (in >= last) return {};
2646
0
            if (in[0].first == OP_IFDUP) {
2647
0
                ++in;
2648
0
                to_parse.emplace_back(DecodeContext::OR_D, -1, -1);
2649
0
            } else {
2650
0
                to_parse.emplace_back(DecodeContext::OR_C, -1, -1);
2651
0
            }
2652
            // or_c and or_d both require X to have type modifier d so, can't contain and_v
2653
0
            to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2654
0
            break;
2655
0
        }
2656
0
        case DecodeContext::ENDIF_ELSE: {
2657
0
            if (in >= last) return {};
2658
0
            if (in[0].first == OP_IF) {
2659
0
                ++in;
2660
0
                BuildBack(ctx.MsContext(), Fragment::OR_I, constructed, /*reverse=*/true);
2661
0
            } else if (in[0].first == OP_NOTIF) {
2662
0
                ++in;
2663
0
                to_parse.emplace_back(DecodeContext::ANDOR, -1, -1);
2664
                // andor requires X to have type modifier d, so it can't be and_v
2665
0
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2666
0
            } else {
2667
0
                return {};
2668
0
            }
2669
0
            break;
2670
0
        }
2671
10.5M
        }
2672
10.5M
    }
2673
3.05k
    if (constructed.size() != 1) return {};
2674
3.05k
    Node tl_node{std::move(constructed.front())};
2675
3.05k
    tl_node.DuplicateKeyCheck(ctx);
2676
    // Note that due to how ComputeType works (only assign the type to the node if the
2677
    // subs' types are valid) this would fail if any node of tree is badly typed.
2678
3.05k
    if (!tl_node.IsValidTopLevel()) return {};
2679
3.05k
    return tl_node;
2680
3.05k
}
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
2297
216
{
2298
    // The two integers are used to hold state for thresh()
2299
216
    std::vector<std::tuple<DecodeContext, int64_t, int64_t>> to_parse;
2300
216
    std::vector<Node<Key>> constructed;
2301
2302
    // This is the top level, so we assume the type is B
2303
    // (in particular, disallowing top level W expressions)
2304
216
    to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2305
2306
8.67k
    while (!to_parse.empty()) {
2307
        // Exit early if the Miniscript is not going to be valid.
2308
8.46k
        if (!constructed.empty() && !constructed.back().IsValid()) return {};
2309
2310
        // Get the current context we are decoding within
2311
8.46k
        auto [cur_context, n, k] = to_parse.back();
2312
8.46k
        to_parse.pop_back();
2313
2314
8.46k
        switch(cur_context) {
2315
2.42k
        case DecodeContext::SINGLE_BKV_EXPR: {
2316
2.42k
            if (in >= last) return {};
2317
2318
            // Constants
2319
2.42k
            if (in[0].first == OP_1) {
2320
0
                ++in;
2321
0
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1);
2322
0
                break;
2323
0
            }
2324
2.42k
            if (in[0].first == OP_0) {
2325
243
                ++in;
2326
243
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0);
2327
243
                break;
2328
243
            }
2329
            // Public keys
2330
2.18k
            if (in[0].second.size() == 33 || in[0].second.size() == 32) {
2331
451
                auto key = ctx.FromPKBytes(in[0].second.begin(), in[0].second.end());
2332
451
                if (!key) return {};
2333
450
                ++in;
2334
450
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_K, Vector(std::move(*key)));
2335
450
                break;
2336
451
            }
2337
1.73k
            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) {
2338
47
                auto key = ctx.FromPKHBytes(in[2].second.begin(), in[2].second.end());
2339
47
                if (!key) return {};
2340
46
                in += 5;
2341
46
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_H, Vector(std::move(*key)));
2342
46
                break;
2343
47
            }
2344
            // Time locks
2345
1.68k
            std::optional<int64_t> num;
2346
1.68k
            if (last - in >= 2 && in[0].first == OP_CHECKSEQUENCEVERIFY && (num = ParseScriptNumber(in[1]))) {
2347
58
                in += 2;
2348
58
                if (*num < 1 || *num > 0x7FFFFFFFL) return {};
2349
58
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num);
2350
58
                break;
2351
58
            }
2352
1.62k
            if (last - in >= 2 && in[0].first == OP_CHECKLOCKTIMEVERIFY && (num = ParseScriptNumber(in[1]))) {
2353
245
                in += 2;
2354
245
                if (num < 1 || num > 0x7FFFFFFFL) return {};
2355
245
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num);
2356
245
                break;
2357
245
            }
2358
            // Hashes
2359
1.38k
            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) {
2360
54
                if (in[2].first == OP_SHA256 && in[1].second.size() == 32) {
2361
18
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, in[1].second);
2362
18
                    in += 7;
2363
18
                    break;
2364
36
                } else if (in[2].first == OP_RIPEMD160 && in[1].second.size() == 20) {
2365
12
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::RIPEMD160, in[1].second);
2366
12
                    in += 7;
2367
12
                    break;
2368
24
                } else if (in[2].first == OP_HASH256 && in[1].second.size() == 32) {
2369
12
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, in[1].second);
2370
12
                    in += 7;
2371
12
                    break;
2372
12
                } else if (in[2].first == OP_HASH160 && in[1].second.size() == 20) {
2373
12
                    constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, in[1].second);
2374
12
                    in += 7;
2375
12
                    break;
2376
12
                }
2377
54
            }
2378
            // Multi
2379
1.32k
            if (last - in >= 3 && in[0].first == OP_CHECKMULTISIG) {
2380
24
                if (IsTapscript(ctx.MsContext())) return {};
2381
24
                std::vector<Key> keys;
2382
24
                const auto n = ParseScriptNumber(in[1]);
2383
24
                if (!n || last - in < 3 + *n) return {};
2384
24
                if (*n < 1 || *n > 20) return {};
2385
72
                for (int i = 0; i < *n; ++i) {
2386
48
                    if (in[2 + i].second.size() != 33) return {};
2387
48
                    auto key = ctx.FromPKBytes(in[2 + i].second.begin(), in[2 + i].second.end());
2388
48
                    if (!key) return {};
2389
48
                    keys.push_back(std::move(*key));
2390
48
                }
2391
24
                const auto k = ParseScriptNumber(in[2 + *n]);
2392
24
                if (!k || *k < 1 || *k > *n) return {};
2393
24
                in += 3 + *n;
2394
24
                std::reverse(keys.begin(), keys.end());
2395
24
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), *k);
2396
24
                break;
2397
24
            }
2398
            // Tapscript's equivalent of multi
2399
1.30k
            if (last - in >= 4 && in[0].first == OP_NUMEQUAL) {
2400
0
                if (!IsTapscript(ctx.MsContext())) return {};
2401
                // The necessary threshold of signatures.
2402
0
                const auto k = ParseScriptNumber(in[1]);
2403
0
                if (!k) return {};
2404
0
                if (*k < 1 || *k > MAX_PUBKEYS_PER_MULTI_A) return {};
2405
0
                if (last - in < 2 + *k * 2) return {};
2406
0
                std::vector<Key> keys;
2407
0
                keys.reserve(*k);
2408
                // Walk through the expected (pubkey, CHECKSIG[ADD]) pairs.
2409
0
                for (int pos = 2;; pos += 2) {
2410
0
                    if (last - in < pos + 2) return {};
2411
                    // Make sure it's indeed an x-only pubkey and a CHECKSIG[ADD], then parse the key.
2412
0
                    if (in[pos].first != OP_CHECKSIGADD && in[pos].first != OP_CHECKSIG) return {};
2413
0
                    if (in[pos + 1].second.size() != 32) return {};
2414
0
                    auto key = ctx.FromPKBytes(in[pos + 1].second.begin(), in[pos + 1].second.end());
2415
0
                    if (!key) return {};
2416
0
                    keys.push_back(std::move(*key));
2417
                    // Make sure early we don't parse an arbitrary large expression.
2418
0
                    if (keys.size() > MAX_PUBKEYS_PER_MULTI_A) return {};
2419
                    // OP_CHECKSIG means it was the last one to parse.
2420
0
                    if (in[pos].first == OP_CHECKSIG) break;
2421
0
                }
2422
0
                if (keys.size() < (size_t)*k) return {};
2423
0
                in += 2 + keys.size() * 2;
2424
0
                std::reverse(keys.begin(), keys.end());
2425
0
                constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), *k);
2426
0
                break;
2427
0
            }
2428
            /** In the following wrappers, we only need to push SINGLE_BKV_EXPR rather
2429
             * than BKV_EXPR, because and_v commutes with these wrappers. For example,
2430
             * c:and_v(X,Y) produces the same script as and_v(X,c:Y). */
2431
            // c: wrapper
2432
1.30k
            if (in[0].first == OP_CHECKSIG) {
2433
493
                ++in;
2434
493
                to_parse.emplace_back(DecodeContext::CHECK, -1, -1);
2435
493
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2436
493
                break;
2437
493
            }
2438
            // v: wrapper
2439
812
            if (in[0].first == OP_VERIFY) {
2440
132
                ++in;
2441
132
                to_parse.emplace_back(DecodeContext::VERIFY, -1, -1);
2442
132
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2443
132
                break;
2444
132
            }
2445
            // n: wrapper
2446
680
            if (in[0].first == OP_0NOTEQUAL) {
2447
267
                ++in;
2448
267
                to_parse.emplace_back(DecodeContext::ZERO_NOTEQUAL, -1, -1);
2449
267
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2450
267
                break;
2451
267
            }
2452
            // Thresh
2453
413
            if (last - in >= 3 && in[0].first == OP_EQUAL && (num = ParseScriptNumber(in[1]))) {
2454
105
                if (*num < 1) return {};
2455
105
                in += 2;
2456
105
                to_parse.emplace_back(DecodeContext::THRESH_W, 0, *num);
2457
105
                break;
2458
105
            }
2459
            // OP_ENDIF can be WRAP_J, WRAP_D, ANDOR, OR_C, OR_D, or OR_I
2460
308
            if (in[0].first == OP_ENDIF) {
2461
299
                ++in;
2462
299
                to_parse.emplace_back(DecodeContext::ENDIF, -1, -1);
2463
299
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2464
299
                break;
2465
299
            }
2466
            /** In and_b and or_b nodes, we only look for SINGLE_BKV_EXPR, because
2467
             * or_b(and_v(X,Y),Z) has script [X] [Y] [Z] OP_BOOLOR, the same as
2468
             * and_v(X,or_b(Y,Z)). In this example, the former of these is invalid as
2469
             * miniscript, while the latter is valid. So we leave the and_v "outside"
2470
             * while decoding. */
2471
            // and_b
2472
9
            if (in[0].first == OP_BOOLAND) {
2473
8
                ++in;
2474
8
                to_parse.emplace_back(DecodeContext::AND_B, -1, -1);
2475
8
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2476
8
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2477
8
                break;
2478
8
            }
2479
            // or_b
2480
1
            if (in[0].first == OP_BOOLOR) {
2481
0
                ++in;
2482
0
                to_parse.emplace_back(DecodeContext::OR_B, -1, -1);
2483
0
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2484
0
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2485
0
                break;
2486
0
            }
2487
            // Unrecognised expression
2488
1
            return {};
2489
1
        }
2490
1.37k
        case DecodeContext::BKV_EXPR: {
2491
1.37k
            to_parse.emplace_back(DecodeContext::MAYBE_AND_V, -1, -1);
2492
1.37k
            to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2493
1.37k
            break;
2494
1
        }
2495
480
        case DecodeContext::W_EXPR: {
2496
            // a: wrapper
2497
480
            if (in >= last) return {};
2498
480
            if (in[0].first == OP_FROMALTSTACK) {
2499
40
                ++in;
2500
40
                to_parse.emplace_back(DecodeContext::ALT, -1, -1);
2501
440
            } else {
2502
440
                to_parse.emplace_back(DecodeContext::SWAP, -1, -1);
2503
440
            }
2504
480
            to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2505
480
            break;
2506
480
        }
2507
1.36k
        case DecodeContext::MAYBE_AND_V: {
2508
            // If we reach a potential AND_V top-level, check if the next part of the script could be another AND_V child
2509
            // These op-codes cannot end any well-formed miniscript so cannot be used in an and_v node.
2510
1.36k
            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) {
2511
108
                to_parse.emplace_back(DecodeContext::AND_V, -1, -1);
2512
                // BKV_EXPR can contain more AND_V nodes
2513
108
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2514
108
            }
2515
1.36k
            break;
2516
480
        }
2517
440
        case DecodeContext::SWAP: {
2518
440
            if (in >= last || in[0].first != OP_SWAP || constructed.empty()) return {};
2519
440
            ++in;
2520
440
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S, Vector(std::move(constructed.back()))};
2521
440
            break;
2522
440
        }
2523
40
        case DecodeContext::ALT: {
2524
40
            if (in >= last || in[0].first != OP_TOALTSTACK || constructed.empty()) return {};
2525
40
            ++in;
2526
40
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A, Vector(std::move(constructed.back()))};
2527
40
            break;
2528
40
        }
2529
492
        case DecodeContext::CHECK: {
2530
492
            if (constructed.empty()) return {};
2531
492
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(std::move(constructed.back()))};
2532
492
            break;
2533
492
        }
2534
24
        case DecodeContext::DUP_IF: {
2535
24
            if (constructed.empty()) return {};
2536
24
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D, Vector(std::move(constructed.back()))};
2537
24
            break;
2538
24
        }
2539
132
        case DecodeContext::VERIFY: {
2540
132
            if (constructed.empty()) return {};
2541
132
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V, Vector(std::move(constructed.back()))};
2542
132
            break;
2543
132
        }
2544
0
        case DecodeContext::NON_ZERO: {
2545
0
            if (constructed.empty()) return {};
2546
0
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J, Vector(std::move(constructed.back()))};
2547
0
            break;
2548
0
        }
2549
267
        case DecodeContext::ZERO_NOTEQUAL: {
2550
267
            if (constructed.empty()) return {};
2551
267
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N, Vector(std::move(constructed.back()))};
2552
267
            break;
2553
267
        }
2554
108
        case DecodeContext::AND_V: {
2555
108
            if (constructed.size() < 2) return {};
2556
108
            BuildBack(ctx.MsContext(), Fragment::AND_V, constructed, /*reverse=*/true);
2557
108
            break;
2558
108
        }
2559
8
        case DecodeContext::AND_B: {
2560
8
            if (constructed.size() < 2) return {};
2561
8
            BuildBack(ctx.MsContext(), Fragment::AND_B, constructed, /*reverse=*/true);
2562
8
            break;
2563
8
        }
2564
0
        case DecodeContext::OR_B: {
2565
0
            if (constructed.size() < 2) return {};
2566
0
            BuildBack(ctx.MsContext(), Fragment::OR_B, constructed, /*reverse=*/true);
2567
0
            break;
2568
0
        }
2569
0
        case DecodeContext::OR_C: {
2570
0
            if (constructed.size() < 2) return {};
2571
0
            BuildBack(ctx.MsContext(), Fragment::OR_C, constructed, /*reverse=*/true);
2572
0
            break;
2573
0
        }
2574
8
        case DecodeContext::OR_D: {
2575
8
            if (constructed.size() < 2) return {};
2576
8
            BuildBack(ctx.MsContext(), Fragment::OR_D, constructed, /*reverse=*/true);
2577
8
            break;
2578
8
        }
2579
44
        case DecodeContext::ANDOR: {
2580
44
            if (constructed.size() < 3) return {};
2581
44
            Node left{std::move(constructed.back())};
2582
44
            constructed.pop_back();
2583
44
            Node right{std::move(constructed.back())};
2584
44
            constructed.pop_back();
2585
44
            Node mid{std::move(constructed.back())};
2586
44
            constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR, Vector(std::move(left), std::move(mid), std::move(right))};
2587
44
            break;
2588
44
        }
2589
577
        case DecodeContext::THRESH_W: {
2590
577
            if (in >= last) return {};
2591
577
            if (in[0].first == OP_ADD) {
2592
472
                ++in;
2593
472
                to_parse.emplace_back(DecodeContext::THRESH_W, n+1, k);
2594
472
                to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2595
472
            } else {
2596
105
                to_parse.emplace_back(DecodeContext::THRESH_E, n+1, k);
2597
                // All children of thresh have type modifier d, so cannot be and_v
2598
105
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2599
105
            }
2600
577
            break;
2601
577
        }
2602
105
        case DecodeContext::THRESH_E: {
2603
105
            if (k < 1 || k > n || constructed.size() < static_cast<size_t>(n)) return {};
2604
105
            std::vector<Node<Key>> subs;
2605
682
            for (int i = 0; i < n; ++i) {
2606
577
                Node sub{std::move(constructed.back())};
2607
577
                constructed.pop_back();
2608
577
                subs.push_back(std::move(sub));
2609
577
            }
2610
105
            constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs), k);
2611
105
            break;
2612
105
        }
2613
299
        case DecodeContext::ENDIF: {
2614
299
            if (in >= last) return {};
2615
2616
            // could be andor or or_i
2617
299
            if (in[0].first == OP_ELSE) {
2618
267
                ++in;
2619
267
                to_parse.emplace_back(DecodeContext::ENDIF_ELSE, -1, -1);
2620
267
                to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2621
267
            }
2622
            // could be j: or d: wrapper
2623
32
            else if (in[0].first == OP_IF) {
2624
24
                if (last - in >= 2 && in[1].first == OP_DUP) {
2625
24
                    in += 2;
2626
24
                    to_parse.emplace_back(DecodeContext::DUP_IF, -1, -1);
2627
24
                } else if (last - in >= 3 && in[1].first == OP_0NOTEQUAL && in[2].first == OP_SIZE) {
2628
0
                    in += 3;
2629
0
                    to_parse.emplace_back(DecodeContext::NON_ZERO, -1, -1);
2630
0
                }
2631
0
                else {
2632
0
                    return {};
2633
0
                }
2634
            // could be or_c or or_d
2635
24
            } else if (in[0].first == OP_NOTIF) {
2636
8
                ++in;
2637
8
                to_parse.emplace_back(DecodeContext::ENDIF_NOTIF, -1, -1);
2638
8
            }
2639
0
            else {
2640
0
                return {};
2641
0
            }
2642
299
            break;
2643
299
        }
2644
299
        case DecodeContext::ENDIF_NOTIF: {
2645
8
            if (in >= last) return {};
2646
8
            if (in[0].first == OP_IFDUP) {
2647
8
                ++in;
2648
8
                to_parse.emplace_back(DecodeContext::OR_D, -1, -1);
2649
8
            } else {
2650
0
                to_parse.emplace_back(DecodeContext::OR_C, -1, -1);
2651
0
            }
2652
            // or_c and or_d both require X to have type modifier d so, can't contain and_v
2653
8
            to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2654
8
            break;
2655
8
        }
2656
267
        case DecodeContext::ENDIF_ELSE: {
2657
267
            if (in >= last) return {};
2658
267
            if (in[0].first == OP_IF) {
2659
223
                ++in;
2660
223
                BuildBack(ctx.MsContext(), Fragment::OR_I, constructed, /*reverse=*/true);
2661
223
            } else if (in[0].first == OP_NOTIF) {
2662
44
                ++in;
2663
44
                to_parse.emplace_back(DecodeContext::ANDOR, -1, -1);
2664
                // andor requires X to have type modifier d, so it can't be and_v
2665
44
                to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2666
44
            } else {
2667
0
                return {};
2668
0
            }
2669
267
            break;
2670
267
        }
2671
8.46k
        }
2672
8.46k
    }
2673
213
    if (constructed.size() != 1) return {};
2674
213
    Node tl_node{std::move(constructed.front())};
2675
213
    tl_node.DuplicateKeyCheck(ctx);
2676
    // Note that due to how ComputeType works (only assign the type to the node if the
2677
    // subs' types are valid) this would fail if any node of tree is badly typed.
2678
213
    if (!tl_node.IsValidTopLevel()) return {};
2679
213
    return tl_node;
2680
213
}
2681
2682
} // namespace internal
2683
2684
template <typename Ctx>
2685
inline std::optional<Node<typename Ctx::Key>> FromString(const std::string& str, const Ctx& ctx)
2686
753
{
2687
753
    return internal::Parse<typename Ctx::Key>(str, ctx);
2688
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
2686
220
{
2687
220
    return internal::Parse<typename Ctx::Key>(str, ctx);
2688
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
2686
533
{
2687
533
    return internal::Parse<typename Ctx::Key>(str, ctx);
2688
533
}
2689
2690
template <typename Ctx>
2691
inline std::optional<Node<typename Ctx::Key>> FromScript(const CScript& script, const Ctx& ctx)
2692
4.02k
{
2693
4.02k
    using namespace internal;
2694
    // A too large Script is necessarily invalid, don't bother parsing it.
2695
4.02k
    if (script.size() > MaxScriptSize(ctx.MsContext())) return {};
2696
4.02k
    auto decomposed = DecomposeScript(script);
2697
4.02k
    if (!decomposed) return {};
2698
4.02k
    auto it = decomposed->begin();
2699
4.02k
    auto ret = DecodeScript<typename Ctx::Key>(it, decomposed->end(), ctx);
2700
4.02k
    if (!ret) return {};
2701
4.00k
    if (it != decomposed->end()) return {};
2702
4.00k
    return ret;
2703
4.00k
}
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
2692
132
{
2693
132
    using namespace internal;
2694
    // A too large Script is necessarily invalid, don't bother parsing it.
2695
132
    if (script.size() > MaxScriptSize(ctx.MsContext())) return {};
2696
132
    auto decomposed = DecomposeScript(script);
2697
132
    if (!decomposed) return {};
2698
128
    auto it = decomposed->begin();
2699
128
    auto ret = DecodeScript<typename Ctx::Key>(it, decomposed->end(), ctx);
2700
128
    if (!ret) return {};
2701
125
    if (it != decomposed->end()) return {};
2702
125
    return ret;
2703
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
2692
624
{
2693
624
    using namespace internal;
2694
    // A too large Script is necessarily invalid, don't bother parsing it.
2695
624
    if (script.size() > MaxScriptSize(ctx.MsContext())) return {};
2696
624
    auto decomposed = DecomposeScript(script);
2697
624
    if (!decomposed) return {};
2698
624
    auto it = decomposed->begin();
2699
624
    auto ret = DecodeScript<typename Ctx::Key>(it, decomposed->end(), ctx);
2700
624
    if (!ret) return {};
2701
611
    if (it != decomposed->end()) return {};
2702
611
    return ret;
2703
611
}
std::optional<miniscript::Node<TapSatisfier::Key>> miniscript::FromScript<TapSatisfier>(CScript const&, TapSatisfier const&)
Line
Count
Source
2692
3.05k
{
2693
3.05k
    using namespace internal;
2694
    // A too large Script is necessarily invalid, don't bother parsing it.
2695
3.05k
    if (script.size() > MaxScriptSize(ctx.MsContext())) return {};
2696
3.05k
    auto decomposed = DecomposeScript(script);
2697
3.05k
    if (!decomposed) return {};
2698
3.05k
    auto it = decomposed->begin();
2699
3.05k
    auto ret = DecodeScript<typename Ctx::Key>(it, decomposed->end(), ctx);
2700
3.05k
    if (!ret) return {};
2701
3.05k
    if (it != decomposed->end()) return {};
2702
3.05k
    return ret;
2703
3.05k
}
std::optional<miniscript::Node<WshSatisfier::Key>> miniscript::FromScript<WshSatisfier>(CScript const&, WshSatisfier const&)
Line
Count
Source
2692
216
{
2693
216
    using namespace internal;
2694
    // A too large Script is necessarily invalid, don't bother parsing it.
2695
216
    if (script.size() > MaxScriptSize(ctx.MsContext())) return {};
2696
216
    auto decomposed = DecomposeScript(script);
2697
216
    if (!decomposed) return {};
2698
216
    auto it = decomposed->begin();
2699
216
    auto ret = DecodeScript<typename Ctx::Key>(it, decomposed->end(), ctx);
2700
216
    if (!ret) return {};
2701
213
    if (it != decomposed->end()) return {};
2702
213
    return ret;
2703
213
}
2704
2705
} // namespace miniscript
2706
2707
#endif // BITCOIN_SCRIPT_MINISCRIPT_H