/ src / test / miniscript_tests.cpp
miniscript_tests.cpp
  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  #include <test/util/random.h>
  6  #include <test/util/setup_common.h>
  7  #include <boost/test/unit_test.hpp>
  8  
  9  #include <addresstype.h>
 10  #include <core_io.h>
 11  #include <hash.h>
 12  #include <pubkey.h>
 13  #include <uint256.h>
 14  #include <crypto/ripemd160.h>
 15  #include <crypto/sha256.h>
 16  #include <script/interpreter.h>
 17  #include <script/miniscript.h>
 18  #include <script/script_error.h>
 19  #include <script/signingprovider.h>
 20  
 21  #include <algorithm>
 22  #include <cstdint>
 23  #include <string>
 24  #include <vector>
 25  
 26  using namespace util::hex_literals;
 27  
 28  namespace {
 29  
 30  /** TestData groups various kinds of precomputed data necessary in this test. */
 31  struct TestData {
 32      //! The only public keys used in this test.
 33      std::vector<CPubKey> pubkeys;
 34      //! A map from the public keys to their CKeyIDs (faster than hashing every time).
 35      std::map<CPubKey, CKeyID> pkhashes;
 36      std::map<CKeyID, CPubKey> pkmap;
 37      std::map<XOnlyPubKey, CKeyID> xonly_pkhashes;
 38      std::map<CPubKey, std::vector<unsigned char>> signatures;
 39      std::map<XOnlyPubKey, std::vector<unsigned char>> schnorr_signatures;
 40  
 41      // Various precomputed hashes
 42      std::vector<std::vector<unsigned char>> sha256;
 43      std::vector<std::vector<unsigned char>> ripemd160;
 44      std::vector<std::vector<unsigned char>> hash256;
 45      std::vector<std::vector<unsigned char>> hash160;
 46      std::map<std::vector<unsigned char>, std::vector<unsigned char>> sha256_preimages;
 47      std::map<std::vector<unsigned char>, std::vector<unsigned char>> ripemd160_preimages;
 48      std::map<std::vector<unsigned char>, std::vector<unsigned char>> hash256_preimages;
 49      std::map<std::vector<unsigned char>, std::vector<unsigned char>> hash160_preimages;
 50  
 51      TestData()
 52      {
 53          // All our signatures sign (and are required to sign) this constant message.
 54          constexpr uint256 MESSAGE_HASH{"0000000000000000f5cd94e18b6fe77dd7aca9e35c2b0c9cbd86356c80a71065"};
 55          // We don't pass additional randomness when creating a schnorr signature.
 56          const auto EMPTY_AUX{uint256::ZERO};
 57  
 58          // We generate 255 public keys and 255 hashes of each type.
 59          for (int i = 1; i <= 255; ++i) {
 60              // This 32-byte array functions as both private key data and hash preimage (31 zero bytes plus any nonzero byte).
 61              unsigned char keydata[32] = {0};
 62              keydata[31] = i;
 63  
 64              // Compute CPubkey and CKeyID
 65              CKey key;
 66              key.Set(keydata, keydata + 32, true);
 67              CPubKey pubkey = key.GetPubKey();
 68              CKeyID keyid = pubkey.GetID();
 69              pubkeys.push_back(pubkey);
 70              pkhashes.emplace(pubkey, keyid);
 71              pkmap.emplace(keyid, pubkey);
 72              XOnlyPubKey xonly_pubkey{pubkey};
 73              uint160 xonly_hash{Hash160(xonly_pubkey)};
 74              xonly_pkhashes.emplace(xonly_pubkey, xonly_hash);
 75              pkmap.emplace(xonly_hash, pubkey);
 76  
 77              // Compute ECDSA signatures on MESSAGE_HASH with the private keys.
 78              std::vector<unsigned char> sig, schnorr_sig(64);
 79              BOOST_CHECK(key.Sign(MESSAGE_HASH, sig));
 80              sig.push_back(1); // sighash byte
 81              signatures.emplace(pubkey, sig);
 82              BOOST_CHECK(key.SignSchnorr(MESSAGE_HASH, schnorr_sig, nullptr, EMPTY_AUX));
 83              schnorr_sig.push_back(1); // Maximally sized Schnorr sigs have a sighash byte.
 84              schnorr_signatures.emplace(XOnlyPubKey{pubkey}, schnorr_sig);
 85  
 86              // Compute various hashes
 87              std::vector<unsigned char> hash;
 88              hash.resize(32);
 89              CSHA256().Write(keydata, 32).Finalize(hash.data());
 90              sha256.push_back(hash);
 91              sha256_preimages[hash] = std::vector<unsigned char>(keydata, keydata + 32);
 92              CHash256().Write(keydata).Finalize(hash);
 93              hash256.push_back(hash);
 94              hash256_preimages[hash] = std::vector<unsigned char>(keydata, keydata + 32);
 95              hash.resize(20);
 96              CRIPEMD160().Write(keydata, 32).Finalize(hash.data());
 97              ripemd160.push_back(hash);
 98              ripemd160_preimages[hash] = std::vector<unsigned char>(keydata, keydata + 32);
 99              CHash160().Write(keydata).Finalize(hash);
100              hash160.push_back(hash);
101              hash160_preimages[hash] = std::vector<unsigned char>(keydata, keydata + 32);
102          }
103      }
104  };
105  
106  //! Global TestData object
107  std::unique_ptr<const TestData> g_testdata;
108  
109  //! A classification of leaf conditions in miniscripts (excluding true/false).
110  enum class ChallengeType {
111      SHA256,
112      RIPEMD160,
113      HASH256,
114      HASH160,
115      OLDER,
116      AFTER,
117      PK
118  };
119  
120  /* With each leaf condition we associate a challenge number.
121   * For hashes it's just the first 4 bytes of the hash. For pubkeys, it's the last 4 bytes.
122   */
123  uint32_t ChallengeNumber(const CPubKey& pubkey) { return ReadLE32(pubkey.data() + 29); }
124  uint32_t ChallengeNumber(const std::vector<unsigned char>& hash) { return ReadLE32(hash.data()); }
125  
126  //! A Challenge is a combination of type of leaf condition and its challenge number.
127  typedef std::pair<ChallengeType, uint32_t> Challenge;
128  
129  /** A class encapulating conversion routing for CPubKey. */
130  struct KeyConverter {
131      typedef CPubKey Key;
132  
133      const miniscript::MiniscriptContext m_script_ctx;
134  
135      constexpr KeyConverter(miniscript::MiniscriptContext ctx) noexcept : m_script_ctx{ctx} {}
136  
137      bool KeyCompare(const Key& a, const Key& b) const {
138          return a < b;
139      }
140  
141      //! Convert a public key to bytes.
142      std::vector<unsigned char> ToPKBytes(const CPubKey& key) const {
143          if (!miniscript::IsTapscript(m_script_ctx)) {
144              return {key.begin(), key.end()};
145          }
146          const XOnlyPubKey xonly_pubkey{key};
147          return {xonly_pubkey.begin(), xonly_pubkey.end()};
148      }
149  
150      //! Convert a public key to its Hash160 bytes (precomputed).
151      std::vector<unsigned char> ToPKHBytes(const CPubKey& key) const {
152          if (!miniscript::IsTapscript(m_script_ctx)) {
153              auto hash = g_testdata->pkhashes.at(key);
154              return {hash.begin(), hash.end()};
155          }
156          const XOnlyPubKey xonly_key{key};
157          auto hash = g_testdata->xonly_pkhashes.at(xonly_key);
158          return {hash.begin(), hash.end()};
159      }
160  
161      //! Parse a public key from a range of hex characters.
162      template<typename I>
163      std::optional<Key> FromString(I first, I last) const {
164          auto bytes = ParseHex(std::string(first, last));
165          Key key{bytes.begin(), bytes.end()};
166          if (key.IsValid()) return key;
167          return {};
168      }
169  
170      template<typename I>
171      std::optional<Key> FromPKBytes(I first, I last) const {
172          if (!miniscript::IsTapscript(m_script_ctx)) {
173              Key key{first, last};
174              if (key.IsValid()) return key;
175              return {};
176          }
177          if (last - first != 32) return {};
178          XOnlyPubKey xonly_pubkey;
179          std::copy(first, last, xonly_pubkey.begin());
180          return xonly_pubkey.GetEvenCorrespondingCPubKey();
181      }
182  
183      template<typename I>
184      std::optional<Key> FromPKHBytes(I first, I last) const {
185          assert(last - first == 20);
186          CKeyID keyid;
187          std::copy(first, last, keyid.begin());
188          return g_testdata->pkmap.at(keyid);
189      }
190  
191      std::optional<std::string> ToString(const Key& key) const {
192          return HexStr(ToPKBytes(key));
193      }
194  
195      miniscript::MiniscriptContext MsContext() const {
196          return m_script_ctx;
197      }
198  };
199  
200  /** A class that encapsulates all signing/hash revealing operations. */
201  struct Satisfier : public KeyConverter {
202  
203      Satisfier(miniscript::MiniscriptContext ctx) noexcept : KeyConverter{ctx} {}
204  
205      //! Which keys/timelocks/hash preimages are available.
206      std::set<Challenge> supported;
207  
208      //! Implement simplified CLTV logic: stack value must exactly match an entry in `supported`.
209      bool CheckAfter(uint32_t value) const {
210          return supported.count(Challenge(ChallengeType::AFTER, value));
211      }
212  
213      //! Implement simplified CSV logic: stack value must exactly match an entry in `supported`.
214      bool CheckOlder(uint32_t value) const {
215          return supported.count(Challenge(ChallengeType::OLDER, value));
216      }
217  
218      //! Produce a signature for the given key.
219      miniscript::Availability Sign(const CPubKey& key, std::vector<unsigned char>& sig) const {
220          if (supported.count(Challenge(ChallengeType::PK, ChallengeNumber(key)))) {
221              if (!miniscript::IsTapscript(m_script_ctx)) {
222                  auto it = g_testdata->signatures.find(key);
223                  if (it == g_testdata->signatures.end()) return miniscript::Availability::NO;
224                  sig = it->second;
225              } else {
226                  auto it = g_testdata->schnorr_signatures.find(XOnlyPubKey{key});
227                  if (it == g_testdata->schnorr_signatures.end()) return miniscript::Availability::NO;
228                  sig = it->second;
229              }
230              return miniscript::Availability::YES;
231          }
232          return miniscript::Availability::NO;
233      }
234  
235      //! Helper function for the various hash based satisfactions.
236      miniscript::Availability SatHash(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage, ChallengeType chtype) const {
237          if (!supported.count(Challenge(chtype, ChallengeNumber(hash)))) return miniscript::Availability::NO;
238          const auto& m =
239              chtype == ChallengeType::SHA256 ? g_testdata->sha256_preimages :
240              chtype == ChallengeType::HASH256 ? g_testdata->hash256_preimages :
241              chtype == ChallengeType::RIPEMD160 ? g_testdata->ripemd160_preimages :
242              g_testdata->hash160_preimages;
243          auto it = m.find(hash);
244          if (it == m.end()) return miniscript::Availability::NO;
245          preimage = it->second;
246          return miniscript::Availability::YES;
247      }
248  
249      // Functions that produce the preimage for hashes of various types.
250      miniscript::Availability SatSHA256(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const { return SatHash(hash, preimage, ChallengeType::SHA256); }
251      miniscript::Availability SatRIPEMD160(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const { return SatHash(hash, preimage, ChallengeType::RIPEMD160); }
252      miniscript::Availability SatHASH256(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const { return SatHash(hash, preimage, ChallengeType::HASH256); }
253      miniscript::Availability SatHASH160(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const { return SatHash(hash, preimage, ChallengeType::HASH160); }
254  };
255  
256  /** Mocking signature/timelock checker.
257   *
258   * It holds a pointer to a Satisfier object, to determine which timelocks are supposed to be available.
259   */
260  class TestSignatureChecker : public BaseSignatureChecker {
261      const Satisfier& ctx;
262  
263  public:
264      TestSignatureChecker(const Satisfier& in_ctx LIFETIMEBOUND) : ctx(in_ctx) {}
265  
266      bool CheckECDSASignature(const std::vector<unsigned char>& sig, const std::vector<unsigned char>& pubkey, const CScript& scriptcode, SigVersion sigversion) const override {
267          CPubKey pk(pubkey);
268          if (!pk.IsValid()) return false;
269          // Instead of actually running signature validation, check if the signature matches the precomputed one for this key.
270          auto it = g_testdata->signatures.find(pk);
271          if (it == g_testdata->signatures.end()) return false;
272          return sig == it->second;
273      }
274  
275      bool CheckSchnorrSignature(std::span<const unsigned char> sig, std::span<const unsigned char> pubkey, SigVersion,
276                                 ScriptExecutionData&, ScriptError*) const override {
277          XOnlyPubKey pk{pubkey};
278          auto it = g_testdata->schnorr_signatures.find(pk);
279          if (it == g_testdata->schnorr_signatures.end()) return false;
280          return std::ranges::equal(sig, it->second);
281      }
282  
283      bool CheckLockTime(const CScriptNum& locktime) const override {
284          // Delegate to Satisfier.
285          return ctx.CheckAfter(locktime.GetInt64());
286      }
287  
288      bool CheckSequence(const CScriptNum& sequence) const override {
289          // Delegate to Satisfier.
290          return ctx.CheckOlder(sequence.GetInt64());
291      }
292  };
293  
294  using Fragment = miniscript::Fragment;
295  using NodeRef = miniscript::NodeRef<CPubKey>;
296  using miniscript::operator""_mst;
297  using Node = miniscript::Node<CPubKey>;
298  
299  /** Compute all challenges (pubkeys, hashes, timelocks) that occur in a given Miniscript. */
300  std::set<Challenge> FindChallenges(const Node* root)
301  {
302      std::set<Challenge> chal;
303  
304      for (std::vector stack{root}; !stack.empty();) {
305          const auto* ref{stack.back()};
306          stack.pop_back();
307  
308          for (const auto& key : ref->keys) {
309              chal.emplace(ChallengeType::PK, ChallengeNumber(key));
310          }
311          switch (ref->fragment) {
312          case Fragment::OLDER: chal.emplace(ChallengeType::OLDER, ref->k); break;
313          case Fragment::AFTER: chal.emplace(ChallengeType::AFTER, ref->k); break;
314          case Fragment::SHA256: chal.emplace(ChallengeType::SHA256, ChallengeNumber(ref->data)); break;
315          case Fragment::RIPEMD160: chal.emplace(ChallengeType::RIPEMD160, ChallengeNumber(ref->data)); break;
316          case Fragment::HASH256: chal.emplace(ChallengeType::HASH256, ChallengeNumber(ref->data)); break;
317          case Fragment::HASH160: chal.emplace(ChallengeType::HASH160, ChallengeNumber(ref->data)); break;
318          default: break;
319          }
320          for (const auto& sub : ref->subs) {
321              stack.push_back(sub.get());
322          }
323      }
324      return chal;
325  }
326  
327  //! The spk for this script under the given context. If it's a Taproot output also record the spend data.
328  CScript ScriptPubKey(miniscript::MiniscriptContext ctx, const CScript& script, TaprootBuilder& builder)
329  {
330      if (!miniscript::IsTapscript(ctx)) return CScript() << OP_0 << WitnessV0ScriptHash(script);
331  
332      // For Taproot outputs we always use a tree with a single script and a dummy internal key.
333      builder.Add(0, script, TAPROOT_LEAF_TAPSCRIPT);
334      builder.Finalize(XOnlyPubKey::NUMS_H);
335      return GetScriptForDestination(builder.GetOutput());
336  }
337  
338  //! Fill the witness with the data additional to the script satisfaction.
339  void SatisfactionToWitness(miniscript::MiniscriptContext ctx, CScriptWitness& witness, const CScript& script, TaprootBuilder& builder) {
340      // For P2WSH, it's only the witness script.
341      witness.stack.emplace_back(script.begin(), script.end());
342      if (!miniscript::IsTapscript(ctx)) return;
343      // For Tapscript we also need the control block.
344      witness.stack.push_back(*builder.GetSpendData().scripts.begin()->second.begin());
345  }
346  
347  struct MiniScriptTest : BasicTestingSetup {
348  /** Run random satisfaction tests. */
349  void TestSatisfy(const KeyConverter& converter, const std::string& testcase, const NodeRef& node) {
350      auto script = node->ToScript(converter);
351      const auto challenges{FindChallenges(node.get())}; // Find all challenges in the generated miniscript.
352      std::vector<Challenge> challist(challenges.begin(), challenges.end());
353      for (int iter = 0; iter < 3; ++iter) {
354          std::shuffle(challist.begin(), challist.end(), m_rng);
355          Satisfier satisfier(converter.MsContext());
356          TestSignatureChecker checker(satisfier);
357          bool prev_mal_success = false, prev_nonmal_success = false;
358          // Go over all challenges involved in this miniscript in random order.
359          for (int add = -1; add < (int)challist.size(); ++add) {
360              if (add >= 0) satisfier.supported.insert(challist[add]); // The first iteration does not add anything
361  
362              // Get the ScriptPubKey for this script, filling spend data if it's Taproot.
363              TaprootBuilder builder;
364              const CScript script_pubkey{ScriptPubKey(converter.MsContext(), script, builder)};
365  
366              // Run malleable satisfaction algorithm.
367              CScriptWitness witness_mal;
368              const bool mal_success = node->Satisfy(satisfier, witness_mal.stack, false) == miniscript::Availability::YES;
369              SatisfactionToWitness(converter.MsContext(), witness_mal, script, builder);
370  
371              // Run non-malleable satisfaction algorithm.
372              CScriptWitness witness_nonmal;
373              const bool nonmal_success = node->Satisfy(satisfier, witness_nonmal.stack, true) == miniscript::Availability::YES;
374              // Compute witness size (excluding script push, control block, and witness count encoding).
375              const uint64_t wit_size{GetSerializeSize(witness_nonmal.stack) - GetSizeOfCompactSize(witness_nonmal.stack.size())};
376              SatisfactionToWitness(converter.MsContext(), witness_nonmal, script, builder);
377  
378              if (nonmal_success) {
379                  // Non-malleable satisfactions are bounded by the satisfaction size plus:
380                  // - For P2WSH spends, the witness script
381                  // - For Tapscript spends, both the witness script and the control block
382                  const size_t max_stack_size{*node->GetStackSize() + 1 + miniscript::IsTapscript(converter.MsContext())};
383                  BOOST_CHECK(witness_nonmal.stack.size() <= max_stack_size);
384                  // If a non-malleable satisfaction exists, the malleable one must also exist, and be identical to it.
385                  BOOST_CHECK(mal_success);
386                  BOOST_CHECK(witness_nonmal.stack == witness_mal.stack);
387                  assert(wit_size <= *node->GetWitnessSize());
388  
389                  // Test non-malleable satisfaction.
390                  ScriptError serror;
391                  bool res = VerifyScript(CScript(), script_pubkey, &witness_nonmal, STANDARD_SCRIPT_VERIFY_FLAGS, checker, &serror);
392                  // Non-malleable satisfactions are guaranteed to be valid if ValidSatisfactions().
393                  if (node->ValidSatisfactions()) BOOST_CHECK(res);
394                  // More detailed: non-malleable satisfactions must be valid, or could fail with ops count error (if CheckOpsLimit failed),
395                  // or with a stack size error (if CheckStackSize check fails).
396                  BOOST_CHECK(res ||
397                              (!node->CheckOpsLimit() && serror == ScriptError::SCRIPT_ERR_OP_COUNT) ||
398                              (!node->CheckStackSize() && serror == ScriptError::SCRIPT_ERR_STACK_SIZE));
399              }
400  
401              if (mal_success && (!nonmal_success || witness_mal.stack != witness_nonmal.stack)) {
402                  // Test malleable satisfaction only if it's different from the non-malleable one.
403                  ScriptError serror;
404                  bool res = VerifyScript(CScript(), script_pubkey, &witness_mal, STANDARD_SCRIPT_VERIFY_FLAGS, checker, &serror);
405                  // Malleable satisfactions are not guaranteed to be valid under any conditions, but they can only
406                  // fail due to stack or ops limits.
407                  BOOST_CHECK(res || serror == ScriptError::SCRIPT_ERR_OP_COUNT || serror == ScriptError::SCRIPT_ERR_STACK_SIZE);
408              }
409  
410              if (node->IsSane()) {
411                  // For sane nodes, the two algorithms behave identically.
412                  BOOST_CHECK_EQUAL(mal_success, nonmal_success);
413              }
414  
415              // Adding more satisfied conditions can never remove our ability to produce a satisfaction.
416              BOOST_CHECK(mal_success >= prev_mal_success);
417              // For nonmalleable solutions this is only true if the added condition is PK;
418              // for other conditions, adding one may make an valid satisfaction become malleable. If the script
419              // is sane, this cannot happen however.
420              if (node->IsSane() || add < 0 || challist[add].first == ChallengeType::PK) {
421                  BOOST_CHECK(nonmal_success >= prev_nonmal_success);
422              }
423              // Remember results for the next added challenge.
424              prev_mal_success = mal_success;
425              prev_nonmal_success = nonmal_success;
426          }
427  
428          bool satisfiable = node->IsSatisfiable([](const Node&) { return true; });
429          // If the miniscript was satisfiable at all, a satisfaction must be found after all conditions are added.
430          BOOST_CHECK_EQUAL(prev_mal_success, satisfiable);
431          // If the miniscript is sane and satisfiable, a nonmalleable satisfaction must eventually be found.
432          if (node->IsSane()) BOOST_CHECK_EQUAL(prev_nonmal_success, satisfiable);
433      }
434  }
435  
436  enum TestMode : int {
437      //! Invalid under any context
438      TESTMODE_INVALID = 0,
439      //! Valid under any context unless overridden
440      TESTMODE_VALID = 1,
441      TESTMODE_NONMAL = 2,
442      TESTMODE_NEEDSIG = 4,
443      TESTMODE_TIMELOCKMIX = 8,
444      //! Invalid only under P2WSH context
445      TESTMODE_P2WSH_INVALID = 16,
446      //! Invalid only under Tapscript context
447      TESTMODE_TAPSCRIPT_INVALID = 32,
448  };
449  
450  void Test(const std::string& ms, const std::string& hexscript, int mode, const KeyConverter& converter,
451            int opslimit = -1, int stacklimit = -1, std::optional<uint32_t> max_wit_size = std::nullopt,
452            std::optional<uint32_t> stack_exec = {})
453  {
454      auto node = miniscript::FromString(ms, converter);
455      const bool is_tapscript{miniscript::IsTapscript(converter.MsContext())};
456      if (mode == TESTMODE_INVALID || ((mode & TESTMODE_P2WSH_INVALID) && !is_tapscript) || ((mode & TESTMODE_TAPSCRIPT_INVALID) && is_tapscript)) {
457          BOOST_CHECK_MESSAGE(!node || !node->IsValid(), "Unexpectedly valid: " + ms);
458      } else {
459          BOOST_CHECK_MESSAGE(node, "Unparseable: " + ms);
460          BOOST_CHECK_MESSAGE(node->IsValid(), "Invalid: " + ms);
461          BOOST_CHECK_MESSAGE(node->IsValidTopLevel(), "Invalid top level: " + ms);
462          auto computed_script = node->ToScript(converter);
463          BOOST_CHECK_MESSAGE(node->ScriptSize() == computed_script.size(), "Script size mismatch: " + ms);
464          if (hexscript != "?") BOOST_CHECK_MESSAGE(HexStr(computed_script) == hexscript, "Script mismatch: " + ms + " (" + HexStr(computed_script) + " vs " + hexscript + ")");
465          BOOST_CHECK_MESSAGE(node->IsNonMalleable() == !!(mode & TESTMODE_NONMAL), "Malleability mismatch: " + ms);
466          BOOST_CHECK_MESSAGE(node->NeedsSignature() == !!(mode & TESTMODE_NEEDSIG), "Signature necessity mismatch: " + ms);
467          BOOST_CHECK_MESSAGE((node->GetType() << "k"_mst) == !(mode & TESTMODE_TIMELOCKMIX), "Timelock mix mismatch: " + ms);
468          auto inferred_miniscript = miniscript::FromScript(computed_script, converter);
469          BOOST_CHECK_MESSAGE(inferred_miniscript, "Cannot infer miniscript from script: " + ms);
470          BOOST_CHECK_MESSAGE(inferred_miniscript->ToScript(converter) == computed_script, "Roundtrip failure: miniscript->script != miniscript->script->miniscript->script: " + ms);
471          if (opslimit != -1) BOOST_CHECK_MESSAGE((int)*node->GetOps() == opslimit, "Ops limit mismatch: " << ms << " (" << *node->GetOps() << " vs " << opslimit << ")");
472          if (stacklimit != -1) BOOST_CHECK_MESSAGE((int)*node->GetStackSize() == stacklimit, "Stack limit mismatch: " << ms << " (" << *node->GetStackSize() << " vs " << stacklimit << ")");
473          if (max_wit_size) BOOST_CHECK_MESSAGE(*node->GetWitnessSize() == *max_wit_size, "Witness size limit mismatch: " << ms << " (" << *node->GetWitnessSize() << " vs " << *max_wit_size << ")");
474          if (stack_exec) BOOST_CHECK_MESSAGE(*node->GetExecStackSize() == *stack_exec, "Stack execution limit mismatch: " << ms << " (" << *node->GetExecStackSize() << " vs " << *stack_exec << ")");
475          TestSatisfy(converter, ms, node);
476      }
477  }
478  
479  void Test(const std::string& ms, const std::string& hexscript, const std::string& hextapscript, int mode,
480            int opslimit, int stacklimit, std::optional<uint32_t> max_wit_size,
481            std::optional<uint32_t> max_tap_wit_size,
482            std::optional<uint32_t> stack_exec)
483  {
484      KeyConverter wsh_converter(miniscript::MiniscriptContext::P2WSH);
485      Test(ms, hexscript, mode, wsh_converter, opslimit, stacklimit, max_wit_size, stack_exec);
486      KeyConverter tap_converter(miniscript::MiniscriptContext::TAPSCRIPT);
487      Test(ms, hextapscript == "=" ? hexscript : hextapscript, mode, tap_converter, opslimit, stacklimit, max_tap_wit_size, stack_exec);
488  }
489  
490  void Test(const std::string& ms, const std::string& hexscript, const std::string& hextapscript, int mode)
491  {
492      Test(ms, hexscript, hextapscript, mode,
493           /*opslimit=*/-1, /*stacklimit=*/-1,
494           /*max_wit_size=*/std::nullopt, /*max_tap_wit_size=*/std::nullopt, /*stack_exec=*/std::nullopt);
495  }
496  }; // struct MiniScriptTest
497  
498  } // namespace
499  
500  BOOST_FIXTURE_TEST_SUITE(miniscript_tests, MiniScriptTest)
501  
502  BOOST_AUTO_TEST_CASE(fixed_tests)
503  {
504      g_testdata.reset(new TestData());
505  
506      // Validity rules
507      Test("l:older(1)", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL); // older(1): valid
508      Test("l:older(0)", "?", "?", TESTMODE_INVALID); // older(0): k must be at least 1
509      Test("l:older(2147483647)", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL); // older(2147483647): valid
510      Test("l:older(2147483648)", "?", "?", TESTMODE_INVALID); // older(2147483648): k must be below 2^31
511      Test("u:after(1)", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL); // after(1): valid
512      Test("u:after(0)", "?", "?", TESTMODE_INVALID); // after(0): k must be at least 1
513      Test("u:after(2147483647)", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL); // after(2147483647): valid
514      Test("u:after(2147483648)", "?", "?", TESTMODE_INVALID); // after(2147483648): k must be below 2^31
515      Test("andor(0,1,1)", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL); // andor(Bdu,B,B): valid
516      Test("andor(a:0,1,1)", "?", "?", TESTMODE_INVALID); // andor(Wdu,B,B): X must be B
517      Test("andor(0,a:1,a:1)", "?", "?", TESTMODE_INVALID); // andor(Bdu,W,W): Y and Z must be B/V/K
518      Test("andor(1,1,1)", "?", "?", TESTMODE_INVALID); // andor(Bu,B,B): X must be d
519      Test("andor(n:or_i(0,after(1)),1,1)", "?", "?", TESTMODE_VALID); // andor(Bdu,B,B): valid
520      Test("andor(or_i(0,after(1)),1,1)", "?", "?", TESTMODE_INVALID); // andor(Bd,B,B): X must be u
521      Test("c:andor(0,pk_k(03a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7),pk_k(036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a00))", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG); // andor(Bdu,K,K): valid
522      Test("t:andor(0,v:1,v:1)", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL); // andor(Bdu,V,V): valid
523      Test("and_v(v:1,1)", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL); // and_v(V,B): valid
524      Test("t:and_v(v:1,v:1)", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL); // and_v(V,V): valid
525      Test("c:and_v(v:1,pk_k(036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a00))", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG); // and_v(V,K): valid
526      Test("and_v(1,1)", "?", "?", TESTMODE_INVALID); // and_v(B,B): X must be V
527      Test("and_v(pk_k(02352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d5),1)", "?", "?", TESTMODE_INVALID); // and_v(K,B): X must be V
528      Test("and_v(v:1,a:1)", "?", "?", TESTMODE_INVALID); // and_v(K,W): Y must be B/V/K
529      Test("and_b(1,a:1)", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL); // and_b(B,W): valid
530      Test("and_b(1,1)", "?", "?", TESTMODE_INVALID); // and_b(B,B): Y must W
531      Test("and_b(v:1,a:1)", "?", "?", TESTMODE_INVALID); // and_b(V,W): X must be B
532      Test("and_b(a:1,a:1)", "?", "?", TESTMODE_INVALID); // and_b(W,W): X must be B
533      Test("and_b(pk_k(025601570cb47f238d2b0286db4a990fa0f3ba28d1a319f5e7cf55c2a2444da7cc),a:1)", "?", "?", TESTMODE_INVALID); // and_b(K,W): X must be B
534      Test("or_b(0,a:0)", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG); // or_b(Bd,Wd): valid
535      Test("or_b(1,a:0)", "?", "?", TESTMODE_INVALID); // or_b(B,Wd): X must be d
536      Test("or_b(0,a:1)", "?", "?", TESTMODE_INVALID); // or_b(Bd,W): Y must be d
537      Test("or_b(0,0)", "?", "?", TESTMODE_INVALID); // or_b(Bd,Bd): Y must W
538      Test("or_b(v:0,a:0)", "?", "?", TESTMODE_INVALID); // or_b(V,Wd): X must be B
539      Test("or_b(a:0,a:0)", "?", "?", TESTMODE_INVALID); // or_b(Wd,Wd): X must be B
540      Test("or_b(pk_k(025601570cb47f238d2b0286db4a990fa0f3ba28d1a319f5e7cf55c2a2444da7cc),a:0)", "?", "?", TESTMODE_INVALID); // or_b(Kd,Wd): X must be B
541      Test("t:or_c(0,v:1)", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL); // or_c(Bdu,V): valid
542      Test("t:or_c(a:0,v:1)", "?", "?", TESTMODE_INVALID); // or_c(Wdu,V): X must be B
543      Test("t:or_c(1,v:1)", "?", "?", TESTMODE_INVALID); // or_c(Bu,V): X must be d
544      Test("t:or_c(n:or_i(0,after(1)),v:1)", "?", "?", TESTMODE_VALID); // or_c(Bdu,V): valid
545      Test("t:or_c(or_i(0,after(1)),v:1)", "?", "?", TESTMODE_INVALID); // or_c(Bd,V): X must be u
546      Test("t:or_c(0,1)", "?", "?", TESTMODE_INVALID); // or_c(Bdu,B): Y must be V
547      Test("or_d(0,1)", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL); // or_d(Bdu,B): valid
548      Test("or_d(a:0,1)", "?", "?", TESTMODE_INVALID); // or_d(Wdu,B): X must be B
549      Test("or_d(1,1)", "?", "?", TESTMODE_INVALID); // or_d(Bu,B): X must be d
550      Test("or_d(n:or_i(0,after(1)),1)", "?", "?", TESTMODE_VALID); // or_d(Bdu,B): valid
551      Test("or_d(or_i(0,after(1)),1)", "?", "?", TESTMODE_INVALID); // or_d(Bd,B): X must be u
552      Test("or_d(0,v:1)", "?", "?", TESTMODE_INVALID); // or_d(Bdu,V): Y must be B
553      Test("or_i(1,1)", "?", "?", TESTMODE_VALID); // or_i(B,B): valid
554      Test("t:or_i(v:1,v:1)", "?", "?", TESTMODE_VALID); // or_i(V,V): valid
555      Test("c:or_i(pk_k(03a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7),pk_k(036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a00))", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG); // or_i(K,K): valid
556      Test("or_i(a:1,a:1)", "?", "?", TESTMODE_INVALID); // or_i(W,W): X and Y must be B/V/K
557      Test("or_b(l:after(100),al:after(1000000000))", "?", "?", TESTMODE_VALID); // or_b(timelock, heighlock) valid
558      Test("and_b(after(100),a:after(1000000000))", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_TIMELOCKMIX); // and_b(timelock, heighlock) invalid
559      Test("pk(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65)", "2103d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65ac", "20d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65ac", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG); // alias to c:pk_k
560      Test("pkh(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65)", "76a914fcd35ddacad9f2d5be5e464639441c6065e6955d88ac", "76a914fd1690c37fa3b0f04395ddc9415b220ab1ccc59588ac", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG); // alias to c:pk_h
561  
562      // Randomly generated test set that covers the majority of type and node type combinations
563      Test("lltvln:after(1231488000)", "6300676300676300670400046749b1926869516868", "=", TESTMODE_VALID | TESTMODE_NONMAL, 12, 3, 3, 3, 3);
564      Test("uuj:and_v(v:multi(2,03d01115d548e7561b15c38f004d734633687cf4419620095bc5b0f47070afe85a,025601570cb47f238d2b0286db4a990fa0f3ba28d1a319f5e7cf55c2a2444da7cc),after(1231488000))", "6363829263522103d01115d548e7561b15c38f004d734633687cf4419620095bc5b0f47070afe85a21025601570cb47f238d2b0286db4a990fa0f3ba28d1a319f5e7cf55c2a2444da7cc52af0400046749b168670068670068", "?", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG | TESTMODE_TAPSCRIPT_INVALID, 14, 5, 2 + 2 + 1 + 2 * 73, 0, 7);
565      Test("or_b(un:multi(2,03daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729,024ce119c96e2fa357200b559b2f7dd5a5f02d5290aff74b03f3e471b273211c97),al:older(16))", "63522103daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee872921024ce119c96e2fa357200b559b2f7dd5a5f02d5290aff74b03f3e471b273211c9752ae926700686b63006760b2686c9b", "?", TESTMODE_VALID | TESTMODE_TAPSCRIPT_INVALID, 14, 5, 2 + 1 + 2 * 73 + 2, 0, 8);
566      Test("j:and_v(vdv:after(1567547623),older(2016))", "829263766304e7e06e5db169686902e007b268", "=", TESTMODE_VALID | TESTMODE_NONMAL, 11, 1, 2, 2, 2);
567      Test("t:and_v(vu:hash256(131772552c01444cd81360818376a040b7c3b2b7b0a53550ee3edde216cec61b),v:sha256(ec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5))", "6382012088aa20131772552c01444cd81360818376a040b7c3b2b7b0a53550ee3edde216cec61b876700686982012088a820ec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc58851", "6382012088aa20131772552c01444cd81360818376a040b7c3b2b7b0a53550ee3edde216cec61b876700686982012088a820ec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc58851", TESTMODE_VALID | TESTMODE_NONMAL, 12, 3, 2 + 33 + 33, 2 + 33 + 33, 4);
568      Test("t:andor(multi(3,02d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e,03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556,02e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd13),v:older(4194305),v:sha256(9267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed2))", "532102d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e2103fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a14602975562102e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd1353ae6482012088a8209267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed2886703010040b2696851", "?", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_TAPSCRIPT_INVALID, 13, 5, 1 + 3 * 73, 0, 10);
569      Test("or_d(multi(1,02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9),or_b(multi(3,022f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01,032fa2104d6b38d11b0230010559879124e42ab8dfeff5ff29dc9cdadd4ecacc3f,03d01115d548e7561b15c38f004d734633687cf4419620095bc5b0f47070afe85a),su:after(500000)))", "512102f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f951ae73645321022f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a0121032fa2104d6b38d11b0230010559879124e42ab8dfeff5ff29dc9cdadd4ecacc3f2103d01115d548e7561b15c38f004d734633687cf4419620095bc5b0f47070afe85a53ae7c630320a107b16700689b68", "?", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_TAPSCRIPT_INVALID, 15, 7, 2 + 1 + 3 * 73 + 1, 0, 10);
570      Test("or_d(sha256(38df1c1f64a24a77b23393bca50dff872e31edc4f3b5aa3b90ad0b82f4f089b6),and_n(un:after(499999999),older(4194305)))", "82012088a82038df1c1f64a24a77b23393bca50dff872e31edc4f3b5aa3b90ad0b82f4f089b68773646304ff64cd1db19267006864006703010040b26868", "82012088a82038df1c1f64a24a77b23393bca50dff872e31edc4f3b5aa3b90ad0b82f4f089b68773646304ff64cd1db19267006864006703010040b26868", TESTMODE_VALID, 16, 1, 33, 33, 3);
571      Test("and_v(or_i(v:multi(2,02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5,03774ae7f858a9411e5ef4246b70c65aac5649980be5c17891bbec17895da008cb),v:multi(2,03e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a,025cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc)),sha256(d1ec675902ef1633427ca360b290b0b3045a0d9058ddb5e648b4c3c3224c5c68))", "63522102c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee52103774ae7f858a9411e5ef4246b70c65aac5649980be5c17891bbec17895da008cb52af67522103e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a21025cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc52af6882012088a820d1ec675902ef1633427ca360b290b0b3045a0d9058ddb5e648b4c3c3224c5c6887", "?", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG | TESTMODE_TAPSCRIPT_INVALID, 11, 5, 2 + 1 + 2 * 73 + 33, 0, 8);
572      Test("j:and_b(multi(2,0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,024ce119c96e2fa357200b559b2f7dd5a5f02d5290aff74b03f3e471b273211c97),s:or_i(older(1),older(4252898)))", "82926352210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821024ce119c96e2fa357200b559b2f7dd5a5f02d5290aff74b03f3e471b273211c9752ae7c6351b26703e2e440b2689a68", "?", TESTMODE_VALID | TESTMODE_NEEDSIG | TESTMODE_TAPSCRIPT_INVALID, 14, 4, 1 + 2 * 73 + 2, 0, 8);
573      Test("and_b(older(16),s:or_d(sha256(e38990d0c7fc009880a9c07c23842e886c6bbdc964ce6bdd5817ad357335ee6f),n:after(1567547623)))", "60b27c82012088a820e38990d0c7fc009880a9c07c23842e886c6bbdc964ce6bdd5817ad357335ee6f87736404e7e06e5db192689a", "=", TESTMODE_VALID, 12, 1, 33, 33, 4);
574      Test("j:and_v(v:hash160(20195b5a3d650c17f0f29f91c33f8f6335193d07),or_d(sha256(96de8fc8c256fa1e1556d41af431cace7dca68707c78dd88c3acab8b17164c47),older(16)))", "82926382012088a91420195b5a3d650c17f0f29f91c33f8f6335193d078882012088a82096de8fc8c256fa1e1556d41af431cace7dca68707c78dd88c3acab8b17164c4787736460b26868", "=", TESTMODE_VALID, 16, 2, 33 + 33, 33 + 33, 4);
575      Test("and_b(hash256(32ba476771d01e37807990ead8719f08af494723de1d228f2c2c07cc0aa40bac),a:and_b(hash256(131772552c01444cd81360818376a040b7c3b2b7b0a53550ee3edde216cec61b),a:older(1)))", "82012088aa2032ba476771d01e37807990ead8719f08af494723de1d228f2c2c07cc0aa40bac876b82012088aa20131772552c01444cd81360818376a040b7c3b2b7b0a53550ee3edde216cec61b876b51b26c9a6c9a", "=", TESTMODE_VALID | TESTMODE_NONMAL, 15, 2, 33 + 33, 33 + 33, 4);
576      Test("thresh(2,multi(2,03a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7,036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a00),a:multi(1,036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a00),ac:pk_k(022f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01))", "522103a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c721036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a0052ae6b5121036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a0051ae6c936b21022f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01ac6c935287", "?", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG | TESTMODE_TAPSCRIPT_INVALID, 13, 6, 1 + 2 * 73 + 1 + 73 + 1, 0, 10);
577      Test("and_n(sha256(d1ec675902ef1633427ca360b290b0b3045a0d9058ddb5e648b4c3c3224c5c68),t:or_i(v:older(4252898),v:older(144)))", "82012088a820d1ec675902ef1633427ca360b290b0b3045a0d9058ddb5e648b4c3c3224c5c68876400676303e2e440b26967029000b269685168", "=", TESTMODE_VALID, 14, 2, 33 + 2, 33 + 2, 4);
578      Test("or_d(nd:and_v(v:older(4252898),v:older(4252898)),sha256(38df1c1f64a24a77b23393bca50dff872e31edc4f3b5aa3b90ad0b82f4f089b6))", "766303e2e440b26903e2e440b2696892736482012088a82038df1c1f64a24a77b23393bca50dff872e31edc4f3b5aa3b90ad0b82f4f089b68768", "=", TESTMODE_VALID, 15, 2, 1 + 33, 1 + 33, 3);
579      Test("c:and_v(or_c(sha256(9267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed2),v:multi(1,02c44d12c7065d812e8acf28d7cbb19f9011ecd9e9fdf281b0e6a3b5e87d22e7db)),pk_k(03acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbe))", "82012088a8209267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed28764512102c44d12c7065d812e8acf28d7cbb19f9011ecd9e9fdf281b0e6a3b5e87d22e7db51af682103acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbeac", "?", TESTMODE_VALID | TESTMODE_NEEDSIG | TESTMODE_TAPSCRIPT_INVALID, 8, 2, 33 + 73, 0, 4);
580      Test("c:and_v(or_c(multi(2,036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a00,02352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d5),v:ripemd160(1b0f3c404d12075c68c938f9f60ebea4f74941a0)),pk_k(03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556))", "5221036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a002102352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d552ae6482012088a6141b0f3c404d12075c68c938f9f60ebea4f74941a088682103fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556ac", "?", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG | TESTMODE_TAPSCRIPT_INVALID, 10, 5, 1 + 2 * 73 + 73, 0, 9);
581      Test("and_v(andor(hash256(8a35d9ca92a48eaade6f53a64985e9e2afeb74dcf8acb4c3721e0dc7e4294b25),v:hash256(939894f70e6c3a25da75da0cc2071b4076d9b006563cf635986ada2e93c0d735),v:older(50000)),after(499999999))", "82012088aa208a35d9ca92a48eaade6f53a64985e9e2afeb74dcf8acb4c3721e0dc7e4294b2587640350c300b2696782012088aa20939894f70e6c3a25da75da0cc2071b4076d9b006563cf635986ada2e93c0d735886804ff64cd1db1", "=", TESTMODE_VALID, 14, 2, 33 + 33, 33 + 33, 4);
582      Test("andor(hash256(5f8d30e655a7ba0d7596bb3ddfb1d2d20390d23b1845000e1e118b3be1b3f040),j:and_v(v:hash160(3a2bff0da9d96868e66abc4427bea4691cf61ccd),older(4194305)),ripemd160(44d90e2d3714c8663b632fcf0f9d5f22192cc4c8))", "82012088aa205f8d30e655a7ba0d7596bb3ddfb1d2d20390d23b1845000e1e118b3be1b3f040876482012088a61444d90e2d3714c8663b632fcf0f9d5f22192cc4c8876782926382012088a9143a2bff0da9d96868e66abc4427bea4691cf61ccd8803010040b26868", "=", TESTMODE_VALID, 20, 2, 33 + 33, 33 + 33, 4);
583      Test("or_i(c:and_v(v:after(500000),pk_k(02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5)),sha256(d9147961436944f43cd99d28b2bbddbf452ef872b30c8279e255e7daafc7f946))", "630320a107b1692102c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5ac6782012088a820d9147961436944f43cd99d28b2bbddbf452ef872b30c8279e255e7daafc7f9468768", "630320a107b16920c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5ac6782012088a820d9147961436944f43cd99d28b2bbddbf452ef872b30c8279e255e7daafc7f9468768", TESTMODE_VALID | TESTMODE_NONMAL, 10, 2, 2 + 73, 2 + 66, 3);
584      Test("thresh(2,c:pk_h(025cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc),s:sha256(e38990d0c7fc009880a9c07c23842e886c6bbdc964ce6bdd5817ad357335ee6f),a:hash160(dd69735817e0e3f6f826a9238dc2e291184f0131))", "76a9145dedfbf9ea599dd4e3ca6a80b333c472fd0b3f6988ac7c82012088a820e38990d0c7fc009880a9c07c23842e886c6bbdc964ce6bdd5817ad357335ee6f87936b82012088a914dd69735817e0e3f6f826a9238dc2e291184f0131876c935287", "76a9141a7ac36cfa8431ab2395d701b0050045ae4a37d188ac7c82012088a820e38990d0c7fc009880a9c07c23842e886c6bbdc964ce6bdd5817ad357335ee6f87936b82012088a914dd69735817e0e3f6f826a9238dc2e291184f0131876c935287", TESTMODE_VALID, 18, 4, 1 + 34 + 33 + 33, 1 + 33 + 33 + 33, 6);
585      Test("and_n(sha256(9267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed2),uc:and_v(v:older(144),pk_k(03fe72c435413d33d48ac09c9161ba8b09683215439d62b7940502bda8b202e6ce)))", "82012088a8209267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed28764006763029000b2692103fe72c435413d33d48ac09c9161ba8b09683215439d62b7940502bda8b202e6ceac67006868", "82012088a8209267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed28764006763029000b26920fe72c435413d33d48ac09c9161ba8b09683215439d62b7940502bda8b202e6ceac67006868", TESTMODE_VALID | TESTMODE_NEEDSIG, 13, 3, 33 + 2 + 73, 33 + 2 + 66, 5);
586      Test("and_n(c:pk_k(03daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729),and_b(l:older(4252898),a:older(16)))", "2103daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729ac64006763006703e2e440b2686b60b26c9a68", "20daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729ac64006763006703e2e440b2686b60b26c9a68", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG | TESTMODE_TIMELOCKMIX, 12, 2, 73 + 1, 66 + 1, 3);
587      Test("c:or_i(and_v(v:older(16),pk_h(02d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e)),pk_h(026a245bf6dc698504c89a20cfded60853152b695336c28063b61c65cbd269e6b4))", "6360b26976a9149fc5dbe5efdce10374a4dd4053c93af540211718886776a9142fbd32c8dd59ee7c17e66cb6ebea7e9846c3040f8868ac", "6360b26976a9144d4421361c3289bdad06441ffaee8be8e786f1ad886776a91460d4a7bcbd08f58e58bd208d1069837d7adb16ae8868ac", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG, 12, 3, 2 + 34 + 73, 2 + 33 + 66, 4);
588      Test("or_d(c:pk_h(02e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd13),andor(c:pk_k(024ce119c96e2fa357200b559b2f7dd5a5f02d5290aff74b03f3e471b273211c97),older(2016),after(1567547623)))", "76a914c42e7ef92fdb603af844d064faad95db9bcdfd3d88ac736421024ce119c96e2fa357200b559b2f7dd5a5f02d5290aff74b03f3e471b273211c97ac6404e7e06e5db16702e007b26868", "76a91421ab1a140d0d305b8ff62bdb887d9fef82c9899e88ac7364204ce119c96e2fa357200b559b2f7dd5a5f02d5290aff74b03f3e471b273211c97ac6404e7e06e5db16702e007b26868", TESTMODE_VALID | TESTMODE_NONMAL, 13, 3, 1 + 34 + 73, 1 + 33 + 66, 5);
589      Test("c:andor(ripemd160(6ad07d21fd5dfc646f0b30577045ce201616b9ba),pk_h(02d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e),and_v(v:hash256(8a35d9ca92a48eaade6f53a64985e9e2afeb74dcf8acb4c3721e0dc7e4294b25),pk_h(03d01115d548e7561b15c38f004d734633687cf4419620095bc5b0f47070afe85a)))", "82012088a6146ad07d21fd5dfc646f0b30577045ce201616b9ba876482012088aa208a35d9ca92a48eaade6f53a64985e9e2afeb74dcf8acb4c3721e0dc7e4294b258876a914dd100be7d9aea5721158ebde6d6a1fd8fff93bb1886776a9149fc5dbe5efdce10374a4dd4053c93af5402117188868ac", "82012088a6146ad07d21fd5dfc646f0b30577045ce201616b9ba876482012088aa208a35d9ca92a48eaade6f53a64985e9e2afeb74dcf8acb4c3721e0dc7e4294b258876a914a63d1e4d2ed109246c600ec8c19cce546b65b1cc886776a9144d4421361c3289bdad06441ffaee8be8e786f1ad8868ac", TESTMODE_VALID | TESTMODE_NEEDSIG, 18, 3, 33 + 34 + 73, 33 + 33 + 66, 5);
590      Test("c:andor(u:ripemd160(6ad07d21fd5dfc646f0b30577045ce201616b9ba),pk_h(03daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729),or_i(pk_h(022f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01),pk_h(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)))", "6382012088a6146ad07d21fd5dfc646f0b30577045ce201616b9ba87670068646376a9149652d86bedf43ad264362e6e6eba6eb764508127886776a914751e76e8199196d454941c45d1b3a323f1433bd688686776a91420d637c1a6404d2227f3561fdbaff5a680dba6488868ac", "6382012088a6146ad07d21fd5dfc646f0b30577045ce201616b9ba87670068646376a914ceedcb44b38bdbcb614d872223964fd3dca8a434886776a914f678d9b79045452c8c64e9309d0f0046056e26c588686776a914a2a75e1819afa208f6c89ae0da43021116dfcb0c8868ac", TESTMODE_VALID | TESTMODE_NEEDSIG, 23, 4, 2 + 33 + 34 + 73, 2 + 33 + 33 + 66, 5);
591      Test("c:or_i(andor(c:pk_h(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65),pk_h(022f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01),pk_h(02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5)),pk_k(02d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e))", "6376a914fcd35ddacad9f2d5be5e464639441c6065e6955d88ac6476a91406afd46bcdfd22ef94ac122aa11f241244a37ecc886776a9149652d86bedf43ad264362e6e6eba6eb7645081278868672102d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e68ac", "6376a914fd1690c37fa3b0f04395ddc9415b220ab1ccc59588ac6476a9149b652a14674a506079f574d20ca7daef6f9a66bb886776a914ceedcb44b38bdbcb614d872223964fd3dca8a43488686720d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e68ac", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG, 17, 5, 2 + 34 + 73 + 34 + 73, 2 + 33 + 66 + 33 + 66, 6);
592      Test("thresh(1,c:pk_k(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65),altv:after(1000000000),altv:after(100))", "2103d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65ac6b6300670400ca9a3bb16951686c936b6300670164b16951686c935187", "20d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65ac6b6300670400ca9a3bb16951686c936b6300670164b16951686c935187", TESTMODE_VALID, 18, 3, 73 + 2 + 2, 66 + 2 + 2, 4);
593      Test("thresh(2,c:pk_k(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65),ac:pk_k(03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556),altv:after(1000000000),altv:after(100))", "2103d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65ac6b2103fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556ac6c936b6300670400ca9a3bb16951686c936b6300670164b16951686c935287", "20d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65ac6b20fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556ac6c936b6300670400ca9a3bb16951686c936b6300670164b16951686c935287", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_TIMELOCKMIX, 22, 4, 73 + 73 + 2 + 2, 66 + 66 + 2 + 2, 5);
594  
595      // Additional Tapscript-related tests
596      // Edge cases when parsing multi_a from script:
597      //  - no pubkey at all
598      //  - no pubkey before a CHECKSIGADD
599      //  - no pubkey before the CHECKSIG
600      constexpr KeyConverter tap_converter{miniscript::MiniscriptContext::TAPSCRIPT};
601      constexpr KeyConverter wsh_converter{miniscript::MiniscriptContext::P2WSH};
602      const auto no_pubkey{"ac519c"_hex_u8};
603      BOOST_CHECK(miniscript::FromScript({no_pubkey.begin(), no_pubkey.end()}, tap_converter) == nullptr);
604      const auto incomplete_multi_a{"ba20c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5ba519c"_hex_u8};
605      BOOST_CHECK(miniscript::FromScript({incomplete_multi_a.begin(), incomplete_multi_a.end()}, tap_converter) == nullptr);
606      const auto incomplete_multi_a_2{"ac2079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac20c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5ba519c"_hex_u8};
607      BOOST_CHECK(miniscript::FromScript({incomplete_multi_a_2.begin(), incomplete_multi_a_2.end()}, tap_converter) == nullptr);
608      // Can use multi_a under Tapscript but not P2WSH.
609      Test("and_v(v:multi_a(2,03d01115d548e7561b15c38f004d734633687cf4419620095bc5b0f47070afe85a,025601570cb47f238d2b0286db4a990fa0f3ba28d1a319f5e7cf55c2a2444da7cc),after(1231488000))", "?", "20d01115d548e7561b15c38f004d734633687cf4419620095bc5b0f47070afe85aac205601570cb47f238d2b0286db4a990fa0f3ba28d1a319f5e7cf55c2a2444da7ccba529d0400046749b1", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG | TESTMODE_P2WSH_INVALID, 4, 2, {}, {}, 3);
610      // Can use more than 20 keys in a multi_a.
611      std::string ms_str_multi_a{"multi_a(1,"};
612      for (size_t i = 0; i < 21; ++i) {
613          ms_str_multi_a += HexStr(g_testdata->pubkeys[i]);
614          if (i < 20) ms_str_multi_a += ",";
615      }
616      ms_str_multi_a += ")";
617      Test(ms_str_multi_a, "?", "2079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac20c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5ba20f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9ba20e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd13ba202f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4ba20fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556ba205cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bcba202f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01ba20acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbeba20a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7ba20774ae7f858a9411e5ef4246b70c65aac5649980be5c17891bbec17895da008cbba20d01115d548e7561b15c38f004d734633687cf4419620095bc5b0f47070afe85aba20f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8ba20499fdf9e895e719cfd64e67f07d38e3226aa7b63678949e6e49b241a60e823e4ba20d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080eba20e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0aba20defdea4cdb677750a420fee807eacf21eb9898ae79b9768766e4faa04a2d4a34ba205601570cb47f238d2b0286db4a990fa0f3ba28d1a319f5e7cf55c2a2444da7ccba202b4ea0a797a443d293ef5cff444f4979f06acfebd7e86d277475656138385b6cba204ce119c96e2fa357200b559b2f7dd5a5f02d5290aff74b03f3e471b273211c97ba20352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d5ba519c", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG | TESTMODE_P2WSH_INVALID, 22, 21, {}, {}, 22);
618      // Since 'd:' is 'u' we can use it directly inside a thresh. But we can't under P2WSH.
619      Test("thresh(2,dv:older(42),s:pk(025cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc),s:pk(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65))", "?", "7663012ab269687c205cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bcac937c20d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65ac935287", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG | TESTMODE_P2WSH_INVALID, 12, 3, {}, {}, 4);
620      // We can have a script that has more than 201 ops (n = 99), that needs a stack size > 100 (n = 110), or has a
621      // script that is larger than 3600 bytes (n = 200). All that can't be under P2WSH.
622      for (const auto pk_count: {99, 110, 200}) {
623          std::string ms_str_large;
624          for (auto i = 0; i < pk_count - 1; ++i) {
625              ms_str_large += "and_b(pk(" + HexStr(g_testdata->pubkeys[i]) + "),a:";
626          }
627          ms_str_large += "pk(" + HexStr(g_testdata->pubkeys[pk_count - 1]) + ")";
628          ms_str_large.insert(ms_str_large.end(), pk_count - 1, ')');
629          Test(ms_str_large, "?", "?", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG | TESTMODE_P2WSH_INVALID, pk_count + (pk_count - 1) * 3, pk_count, {}, {}, pk_count + 1);
630      }
631      // We can have a script that reaches a stack size of 1000 during execution.
632      std::string ms_stack_limit;
633      auto count{998};
634      for (auto i = 0; i < count; ++i) {
635          ms_stack_limit += "and_b(older(1),a:";
636      }
637      ms_stack_limit += "pk(" + HexStr(g_testdata->pubkeys[0]) + ")";
638      ms_stack_limit.insert(ms_stack_limit.end(), count, ')');
639      const auto ms_stack_ok{miniscript::FromString(ms_stack_limit, tap_converter)};
640      BOOST_CHECK(ms_stack_ok && ms_stack_ok->CheckStackSize());
641      Test(ms_stack_limit, "?", "?", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG | TESTMODE_P2WSH_INVALID, 4 * count + 1, 1, {}, {}, 1 + count + 1);
642      // But one more element on the stack during execution will make it fail. And we'd detect that.
643      count++;
644      ms_stack_limit = "and_b(older(1),a:" + ms_stack_limit + ")";
645      const auto ms_stack_nok{miniscript::FromString(ms_stack_limit, tap_converter)};
646      BOOST_CHECK(ms_stack_nok && !ms_stack_nok->CheckStackSize());
647      Test(ms_stack_limit, "?", "?", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG | TESTMODE_P2WSH_INVALID, 4 * count + 1, 1, {}, {}, 1 + count + 1);
648  
649      // Misc unit tests
650      // A Script with a non minimal push is invalid
651      constexpr auto nonminpush{"0000210232780000feff00ffffffffffff21ff005f00ae21ae00000000060602060406564c2102320000060900fe00005f00ae21ae00100000060606060606000000000000000000000000000000000000000000000000000000000000000000"_hex_u8};
652      const CScript nonminpush_script(nonminpush.begin(), nonminpush.end());
653      BOOST_CHECK(miniscript::FromScript(nonminpush_script, wsh_converter) == nullptr);
654      BOOST_CHECK(miniscript::FromScript(nonminpush_script, tap_converter) == nullptr);
655      // A non-minimal VERIFY (<key> CHECKSIG VERIFY 1)
656      constexpr auto nonminverify{"2103a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7ac6951"_hex_u8};
657      const CScript nonminverify_script(nonminverify.begin(), nonminverify.end());
658      BOOST_CHECK(miniscript::FromScript(nonminverify_script, wsh_converter) == nullptr);
659      BOOST_CHECK(miniscript::FromScript(nonminverify_script, tap_converter) == nullptr);
660      // A threshold as large as the number of subs is valid.
661      Test("thresh(2,c:pk_k(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65),altv:after(100))", "2103d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65ac6b6300670164b16951686c935287", "20d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65ac6b6300670164b16951686c935287", TESTMODE_VALID | TESTMODE_NEEDSIG | TESTMODE_NONMAL);
662      // A threshold of 1 is valid.
663      Test("thresh(1,c:pk_k(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65),sc:pk_k(03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556))", "2103d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65ac7c2103fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556ac935187", "20d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65ac7c20fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556ac935187", TESTMODE_VALID | TESTMODE_NEEDSIG | TESTMODE_NONMAL);
664      // A threshold with a k larger than the number of subs is invalid
665      Test("thresh(3,c:pk_k(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65),sc:pk_k(03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556))", "2103d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65ac7c2103fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556ac935187", "=", TESTMODE_INVALID);
666      // A threshold with a k null is invalid
667      Test("thresh(0,c:pk_k(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65),sc:pk_k(03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556))", "2103d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65ac7c2103fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556ac935187", "=", TESTMODE_INVALID);
668      // For CHECKMULTISIG the OP cost is the number of keys, but the stack size is the number of sigs (+1)
669      const auto ms_multi = miniscript::FromString("multi(1,03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65,03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556,0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)", wsh_converter);
670      BOOST_CHECK(ms_multi);
671      BOOST_CHECK_EQUAL(*ms_multi->GetOps(), 4); // 3 pubkeys + CMS
672      BOOST_CHECK_EQUAL(*ms_multi->GetStackSize(), 2); // 1 sig + dummy elem
673      // The 'd:' wrapper leaves on the stack what was DUP'ed at the beginning of its execution.
674      // Since it contains an OP_IF just after on the same element, we can make sure that the element
675      // in question must be OP_1 if OP_IF enforces that its argument must only be OP_1 or the empty
676      // vector (since otherwise the execution would immediately fail). This is the MINIMALIF rule.
677      // Unfortunately, this rule is consensus for Taproot but only policy for P2WSH. Therefore we can't
678      // (for now) have 'd:' be 'u'. This tests we can't use a 'd:' wrapper for a thresh, which requires
679      // its subs to all be 'u' (taken from https://github.com/rust-bitcoin/rust-miniscript/discussions/341).
680      const auto ms_minimalif = miniscript::FromString("thresh(3,c:pk_k(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65),sc:pk_k(03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556),sc:pk_k(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798),sdv:older(32))", wsh_converter);
681      BOOST_CHECK(ms_minimalif && !ms_minimalif->IsValid());
682      // A Miniscript with duplicate keys is not sane
683      const auto ms_dup1 = miniscript::FromString("and_v(v:pk(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65),pk(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65))", wsh_converter);
684      BOOST_CHECK(ms_dup1);
685      BOOST_CHECK(!ms_dup1->IsSane() && !ms_dup1->CheckDuplicateKey());
686      // Same with a disjunction, and different key nodes (pk and pkh)
687      const auto ms_dup2 = miniscript::FromString("or_b(c:pk_k(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65),ac:pk_h(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65))", wsh_converter);
688      BOOST_CHECK(ms_dup2 && !ms_dup2->IsSane() && !ms_dup2->CheckDuplicateKey());
689      // Same when the duplicates are leaves or a larger tree
690      const auto ms_dup3 = miniscript::FromString("or_i(and_b(pk(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65),s:pk(03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556)),and_b(older(1),s:pk(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65)))", wsh_converter);
691      BOOST_CHECK(ms_dup3 && !ms_dup3->IsSane() && !ms_dup3->CheckDuplicateKey());
692      // Same when the duplicates are on different levels in the tree
693      const auto ms_dup4 = miniscript::FromString("thresh(2,pkh(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65),s:pk(03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556),a:and_b(dv:older(1),s:pk(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65)))", wsh_converter);
694      BOOST_CHECK(ms_dup4 && !ms_dup4->IsSane() && !ms_dup4->CheckDuplicateKey());
695      // Sanity check the opposite is true, too. An otherwise sane Miniscript with no duplicate keys is sane.
696      const auto ms_nondup = miniscript::FromString("pk(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65)", wsh_converter);
697      BOOST_CHECK(ms_nondup && ms_nondup->CheckDuplicateKey() && ms_nondup->IsSane());
698      // Test we find the first insane sub closer to be a leaf node. This fragment is insane for two reasons:
699      // 1. It can be spent without a signature
700      // 2. It contains timelock mixes
701      // We'll report the timelock mix error, as it's "deeper" (closer to be a leaf node) than the "no 's' property"
702      // error is.
703      const auto ms_ins = miniscript::FromString("or_i(and_b(after(1),a:after(1000000000)),pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204))", wsh_converter);
704      BOOST_CHECK(ms_ins && ms_ins->IsValid() && !ms_ins->IsSane());
705      const auto insane_sub = ms_ins->FindInsaneSub();
706      BOOST_CHECK(insane_sub && *insane_sub->ToString(wsh_converter) == "and_b(after(1),a:after(1000000000))");
707  
708      // Numbers can't be prefixed by a sign.
709      BOOST_CHECK(!miniscript::FromString("after(-1)", wsh_converter));
710      BOOST_CHECK(!miniscript::FromString("after(+1)", wsh_converter));
711      BOOST_CHECK(!miniscript::FromString("thresh(-1,pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204))", wsh_converter));
712      BOOST_CHECK(!miniscript::FromString("multi(+1,03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204)", wsh_converter));
713  
714      // Timelock tests
715      Test("after(100)", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL); // only heightlock
716      Test("after(1000000000)", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL); // only timelock
717      Test("or_b(l:after(100),al:after(1000000000))", "?", "?", TESTMODE_VALID); // or_b(timelock, heighlock) valid
718      Test("and_b(after(100),a:after(1000000000))", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_TIMELOCKMIX); // and_b(timelock, heighlock) invalid
719      /* This is correctly detected as non-malleable but for the wrong reason. The type system assumes that branches 1 and 2
720         can be spent together to create a non-malleble witness, but because of mixing of timelocks they cannot be spent together.
721         But since exactly one of the two after's can be satisfied, the witness involving the key cannot be malleated.
722      */
723      Test("thresh(2,ltv:after(1000000000),altv:after(100),a:pk(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65))", "?", "?", TESTMODE_VALID | TESTMODE_TIMELOCKMIX | TESTMODE_NONMAL); // thresh with k = 2
724      // This is actually non-malleable in practice, but we cannot detect it in type system. See above rationale
725      Test("thresh(1,c:pk_k(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65),altv:after(1000000000),altv:after(100))", "?", "?", TESTMODE_VALID); // thresh with k = 1
726  
727      g_testdata.reset();
728  }
729  
730  BOOST_AUTO_TEST_SUITE_END()