miniscript_tests.cpp raw

   1  // Copyright (c) 2019-2022 The Limenka 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(Span<const unsigned char> sig, 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 NodeRef& root)
 301  {
 302      std::set<Challenge> chal;
 303  
 304      for (std::vector stack{root.get()}; !stack.empty();) {
 305          const Node* ref{stack.back()};
 306          stack.pop_back();
 307  
 308      for (const auto& key : ref->keys) {
 309          chal.emplace(ChallengeType::PK, ChallengeNumber(key));
 310      }
 311      if (ref->fragment == miniscript::Fragment::OLDER) {
 312          chal.emplace(ChallengeType::OLDER, ref->k);
 313      } else if (ref->fragment == miniscript::Fragment::AFTER) {
 314          chal.emplace(ChallengeType::AFTER, ref->k);
 315      } else if (ref->fragment == miniscript::Fragment::SHA256) {
 316          chal.emplace(ChallengeType::SHA256, ChallengeNumber(ref->data));
 317      } else if (ref->fragment == miniscript::Fragment::RIPEMD160) {
 318          chal.emplace(ChallengeType::RIPEMD160, ChallengeNumber(ref->data));
 319      } else if (ref->fragment == miniscript::Fragment::HASH256) {
 320          chal.emplace(ChallengeType::HASH256, ChallengeNumber(ref->data));
 321      } else if (ref->fragment == miniscript::Fragment::HASH160) {
 322          chal.emplace(ChallengeType::HASH160, ChallengeNumber(ref->data));
 323      }
 324      for (const auto& sub : ref->subs) {
 325              stack.push_back(sub.get());
 326          }
 327      }
 328      return chal;
 329  }
 330  
 331  //! The spk for this script under the given context. If it's a Taproot output also record the spend data.
 332  CScript ScriptPubKey(miniscript::MiniscriptContext ctx, const CScript& script, TaprootBuilder& builder)
 333  {
 334      if (!miniscript::IsTapscript(ctx)) return CScript() << OP_0 << WitnessV0ScriptHash(script);
 335  
 336      // For Taproot outputs we always use a tree with a single script and a dummy internal key.
 337      builder.Add(0, script, TAPROOT_LEAF_TAPSCRIPT);
 338      builder.Finalize(XOnlyPubKey::NUMS_H);
 339      return GetScriptForDestination(builder.GetOutput());
 340  }
 341  
 342  //! Fill the witness with the data additional to the script satisfaction.
 343  void SatisfactionToWitness(miniscript::MiniscriptContext ctx, CScriptWitness& witness, const CScript& script, TaprootBuilder& builder) {
 344      // For P2WSH, it's only the witness script.
 345      witness.stack.emplace_back(script.begin(), script.end());
 346      if (!miniscript::IsTapscript(ctx)) return;
 347      // For Tapscript we also need the control block.
 348      witness.stack.push_back(*builder.GetSpendData().scripts.begin()->second.begin());
 349  }
 350  
 351  struct MiniScriptTest : BasicTestingSetup {
 352  /** Run random satisfaction tests. */
 353  void TestSatisfy(const KeyConverter& converter, const std::string& testcase, const NodeRef& node) {
 354      auto script = node->ToScript(converter);
 355      auto challenges = FindChallenges(node); // Find all challenges in the generated miniscript.
 356      std::vector<Challenge> challist(challenges.begin(), challenges.end());
 357      for (int iter = 0; iter < 3; ++iter) {
 358          std::shuffle(challist.begin(), challist.end(), m_rng);
 359          Satisfier satisfier(converter.MsContext());
 360          TestSignatureChecker checker(satisfier);
 361          bool prev_mal_success = false, prev_nonmal_success = false;
 362          // Go over all challenges involved in this miniscript in random order.
 363          for (int add = -1; add < (int)challist.size(); ++add) {
 364              if (add >= 0) satisfier.supported.insert(challist[add]); // The first iteration does not add anything
 365  
 366              // Get the ScriptPubKey for this script, filling spend data if it's Taproot.
 367              TaprootBuilder builder;
 368              const CScript script_pubkey{ScriptPubKey(converter.MsContext(), script, builder)};
 369  
 370              // Run malleable satisfaction algorithm.
 371              CScriptWitness witness_mal;
 372              const bool mal_success = node->Satisfy(satisfier, witness_mal.stack, false) == miniscript::Availability::YES;
 373              SatisfactionToWitness(converter.MsContext(), witness_mal, script, builder);
 374  
 375              // Run non-malleable satisfaction algorithm.
 376              CScriptWitness witness_nonmal;
 377              const bool nonmal_success = node->Satisfy(satisfier, witness_nonmal.stack, true) == miniscript::Availability::YES;
 378              // Compute witness size (excluding script push, control block, and witness count encoding).
 379              const size_t wit_size = GetSerializeSize(witness_nonmal.stack) - GetSizeOfCompactSize(witness_nonmal.stack.size());
 380              SatisfactionToWitness(converter.MsContext(), witness_nonmal, script, builder);
 381  
 382              if (nonmal_success) {
 383                  // Non-malleable satisfactions are bounded by the satisfaction size plus:
 384                  // - For P2WSH spends, the witness script
 385                  // - For Tapscript spends, both the witness script and the control block
 386                  const size_t max_stack_size{*node->GetStackSize() + 1 + miniscript::IsTapscript(converter.MsContext())};
 387                  BOOST_CHECK(witness_nonmal.stack.size() <= max_stack_size);
 388                  // If a non-malleable satisfaction exists, the malleable one must also exist, and be identical to it.
 389                  BOOST_CHECK(mal_success);
 390                  BOOST_CHECK(witness_nonmal.stack == witness_mal.stack);
 391                  assert(wit_size <= *node->GetWitnessSize());
 392  
 393                  // Test non-malleable satisfaction.
 394                  ScriptError serror;
 395                  bool res = VerifyScript(CScript(), script_pubkey, &witness_nonmal, STANDARD_SCRIPT_VERIFY_FLAGS, checker, &serror);
 396                  // Non-malleable satisfactions are guaranteed to be valid if ValidSatisfactions(), unless REDUCED_DATA rules are violated.
 397                  if (node->ValidSatisfactions()) {
 398                      BOOST_CHECK(res ||
 399                                  serror == ScriptError::SCRIPT_ERR_PUSH_SIZE ||
 400                                  serror == ScriptError::SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM ||
 401                                  serror == ScriptError::SCRIPT_ERR_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION ||
 402                                  serror == ScriptError::SCRIPT_ERR_DISCOURAGE_OP_SUCCESS ||
 403                                  serror == ScriptError::SCRIPT_ERR_TAPSCRIPT_MINIMALIF);
 404                  }
 405                  // More detailed: non-malleable satisfactions must be valid, or could fail with ops count error (if CheckOpsLimit failed),
 406                  // or with a stack size error (if CheckStackSize check fails), or with REDUCED_DATA-related errors.
 407                  BOOST_CHECK(res ||
 408                              (!node->CheckOpsLimit() && serror == ScriptError::SCRIPT_ERR_OP_COUNT) ||
 409                              (!node->CheckStackSize() && serror == ScriptError::SCRIPT_ERR_STACK_SIZE) ||
 410                              (serror == ScriptError::SCRIPT_ERR_PUSH_SIZE) ||
 411                              (serror == ScriptError::SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) ||
 412                              (serror == ScriptError::SCRIPT_ERR_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION) ||
 413                              (serror == ScriptError::SCRIPT_ERR_DISCOURAGE_OP_SUCCESS) ||
 414                              (serror == ScriptError::SCRIPT_ERR_TAPSCRIPT_MINIMALIF));
 415              }
 416  
 417              if (mal_success && (!nonmal_success || witness_mal.stack != witness_nonmal.stack)) {
 418                  // Test malleable satisfaction only if it's different from the non-malleable one.
 419                  ScriptError serror;
 420                  bool res = VerifyScript(CScript(), script_pubkey, &witness_mal, STANDARD_SCRIPT_VERIFY_FLAGS, checker, &serror);
 421                  // Malleable satisfactions are not guaranteed to be valid under any conditions, but they can only
 422                  // fail due to stack or ops limits, or REDUCED_DATA-related errors.
 423                  BOOST_CHECK(res ||
 424                              serror == ScriptError::SCRIPT_ERR_OP_COUNT ||
 425                              serror == ScriptError::SCRIPT_ERR_STACK_SIZE ||
 426                              serror == ScriptError::SCRIPT_ERR_PUSH_SIZE ||
 427                              serror == ScriptError::SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM ||
 428                              serror == ScriptError::SCRIPT_ERR_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION ||
 429                              serror == ScriptError::SCRIPT_ERR_DISCOURAGE_OP_SUCCESS ||
 430                              serror == ScriptError::SCRIPT_ERR_TAPSCRIPT_MINIMALIF);
 431              }
 432  
 433              if (node->IsSane()) {
 434                  // For sane nodes, the two algorithms behave identically.
 435                  BOOST_CHECK_EQUAL(mal_success, nonmal_success);
 436              }
 437  
 438              // Adding more satisfied conditions can never remove our ability to produce a satisfaction.
 439              BOOST_CHECK(mal_success >= prev_mal_success);
 440              // For nonmalleable solutions this is only true if the added condition is PK;
 441              // for other conditions, adding one may make an valid satisfaction become malleable. If the script
 442              // is sane, this cannot happen however.
 443              if (node->IsSane() || add < 0 || challist[add].first == ChallengeType::PK) {
 444                  BOOST_CHECK(nonmal_success >= prev_nonmal_success);
 445              }
 446              // Remember results for the next added challenge.
 447              prev_mal_success = mal_success;
 448              prev_nonmal_success = nonmal_success;
 449          }
 450  
 451          bool satisfiable = node->IsSatisfiable([](const Node&) { return true; });
 452          // If the miniscript was satisfiable at all, a satisfaction must be found after all conditions are added.
 453          BOOST_CHECK_EQUAL(prev_mal_success, satisfiable);
 454          // If the miniscript is sane and satisfiable, a nonmalleable satisfaction must eventually be found.
 455          if (node->IsSane()) BOOST_CHECK_EQUAL(prev_nonmal_success, satisfiable);
 456      }
 457  }
 458  
 459  enum TestMode : int {
 460      //! Invalid under any context
 461      TESTMODE_INVALID = 0,
 462      //! Valid under any context unless overridden
 463      TESTMODE_VALID = 1,
 464      TESTMODE_NONMAL = 2,
 465      TESTMODE_NEEDSIG = 4,
 466      TESTMODE_TIMELOCKMIX = 8,
 467      //! Invalid only under P2WSH context
 468      TESTMODE_P2WSH_INVALID = 16,
 469      //! Invalid only under Tapscript context
 470      TESTMODE_TAPSCRIPT_INVALID = 32,
 471  };
 472  
 473  void Test(const std::string& ms, const std::string& hexscript, int mode, const KeyConverter& converter,
 474            int opslimit = -1, int stacklimit = -1, std::optional<uint32_t> max_wit_size = std::nullopt,
 475            std::optional<uint32_t> stack_exec = {})
 476  {
 477      auto node = miniscript::FromString(ms, converter);
 478      const bool is_tapscript{miniscript::IsTapscript(converter.MsContext())};
 479      if (mode == TESTMODE_INVALID || ((mode & TESTMODE_P2WSH_INVALID) && !is_tapscript) || ((mode & TESTMODE_TAPSCRIPT_INVALID) && is_tapscript)) {
 480          BOOST_CHECK_MESSAGE(!node || !node->IsValid(), "Unexpectedly valid: " + ms);
 481      } else {
 482          BOOST_CHECK_MESSAGE(node, "Unparseable: " + ms);
 483          BOOST_CHECK_MESSAGE(node->IsValid(), "Invalid: " + ms);
 484          BOOST_CHECK_MESSAGE(node->IsValidTopLevel(), "Invalid top level: " + ms);
 485          auto computed_script = node->ToScript(converter);
 486          BOOST_CHECK_MESSAGE(node->ScriptSize() == computed_script.size(), "Script size mismatch: " + ms);
 487          if (hexscript != "?") BOOST_CHECK_MESSAGE(HexStr(computed_script) == hexscript, "Script mismatch: " + ms + " (" + HexStr(computed_script) + " vs " + hexscript + ")");
 488          BOOST_CHECK_MESSAGE(node->IsNonMalleable() == !!(mode & TESTMODE_NONMAL), "Malleability mismatch: " + ms);
 489          BOOST_CHECK_MESSAGE(node->NeedsSignature() == !!(mode & TESTMODE_NEEDSIG), "Signature necessity mismatch: " + ms);
 490          BOOST_CHECK_MESSAGE((node->GetType() << "k"_mst) == !(mode & TESTMODE_TIMELOCKMIX), "Timelock mix mismatch: " + ms);
 491          auto inferred_miniscript = miniscript::FromScript(computed_script, converter);
 492          BOOST_CHECK_MESSAGE(inferred_miniscript, "Cannot infer miniscript from script: " + ms);
 493          BOOST_CHECK_MESSAGE(inferred_miniscript->ToScript(converter) == computed_script, "Roundtrip failure: miniscript->script != miniscript->script->miniscript->script: " + ms);
 494          if (opslimit != -1) BOOST_CHECK_MESSAGE((int)*node->GetOps() == opslimit, "Ops limit mismatch: " << ms << " (" << *node->GetOps() << " vs " << opslimit << ")");
 495          if (stacklimit != -1) BOOST_CHECK_MESSAGE((int)*node->GetStackSize() == stacklimit, "Stack limit mismatch: " << ms << " (" << *node->GetStackSize() << " vs " << stacklimit << ")");
 496          if (max_wit_size) BOOST_CHECK_MESSAGE(*node->GetWitnessSize() == *max_wit_size, "Witness size limit mismatch: " << ms << " (" << *node->GetWitnessSize() << " vs " << *max_wit_size << ")");
 497          if (stack_exec) BOOST_CHECK_MESSAGE(*node->GetExecStackSize() == *stack_exec, "Stack execution limit mismatch: " << ms << " (" << *node->GetExecStackSize() << " vs " << *stack_exec << ")");
 498          TestSatisfy(converter, ms, node);
 499      }
 500  }
 501  
 502  void Test(const std::string& ms, const std::string& hexscript, const std::string& hextapscript, int mode,
 503            int opslimit, int stacklimit, std::optional<uint32_t> max_wit_size,
 504            std::optional<uint32_t> max_tap_wit_size,
 505            std::optional<uint32_t> stack_exec)
 506  {
 507      KeyConverter wsh_converter(miniscript::MiniscriptContext::P2WSH);
 508      Test(ms, hexscript, mode, wsh_converter, opslimit, stacklimit, max_wit_size, stack_exec);
 509      KeyConverter tap_converter(miniscript::MiniscriptContext::TAPSCRIPT);
 510      Test(ms, hextapscript == "=" ? hexscript : hextapscript, mode, tap_converter, opslimit, stacklimit, max_tap_wit_size, stack_exec);
 511  }
 512  
 513  void Test(const std::string& ms, const std::string& hexscript, const std::string& hextapscript, int mode)
 514  {
 515      Test(ms, hexscript, hextapscript, mode,
 516           /*opslimit=*/-1, /*stacklimit=*/-1,
 517           /*max_wit_size=*/std::nullopt, /*max_tap_wit_size=*/std::nullopt, /*stack_exec=*/std::nullopt);
 518  }
 519  }; // struct MiniScriptTest
 520  
 521  } // namespace
 522  
 523  BOOST_FIXTURE_TEST_SUITE(miniscript_tests, MiniScriptTest)
 524  
 525  BOOST_AUTO_TEST_CASE(fixed_tests)
 526  {
 527      g_testdata.reset(new TestData());
 528  
 529      // Validity rules
 530      Test("l:older(1)", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL); // older(1): valid
 531      Test("l:older(0)", "?", "?", TESTMODE_INVALID); // older(0): k must be at least 1
 532      Test("l:older(2147483647)", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL); // older(2147483647): valid
 533      Test("l:older(2147483648)", "?", "?", TESTMODE_INVALID); // older(2147483648): k must be below 2^31
 534      Test("u:after(1)", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL); // after(1): valid
 535      Test("u:after(0)", "?", "?", TESTMODE_INVALID); // after(0): k must be at least 1
 536      Test("u:after(2147483647)", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL); // after(2147483647): valid
 537      Test("u:after(2147483648)", "?", "?", TESTMODE_INVALID); // after(2147483648): k must be below 2^31
 538      Test("andor(0,1,1)", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL); // andor(Bdu,B,B): valid
 539      Test("andor(a:0,1,1)", "?", "?", TESTMODE_INVALID); // andor(Wdu,B,B): X must be B
 540      Test("andor(0,a:1,a:1)", "?", "?", TESTMODE_INVALID); // andor(Bdu,W,W): Y and Z must be B/V/K
 541      Test("andor(1,1,1)", "?", "?", TESTMODE_INVALID); // andor(Bu,B,B): X must be d
 542      Test("andor(n:or_i(0,after(1)),1,1)", "?", "?", TESTMODE_VALID); // andor(Bdu,B,B): valid
 543      Test("andor(or_i(0,after(1)),1,1)", "?", "?", TESTMODE_INVALID); // andor(Bd,B,B): X must be u
 544      Test("c:andor(0,pk_k(03a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7),pk_k(036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a00))", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG); // andor(Bdu,K,K): valid
 545      Test("t:andor(0,v:1,v:1)", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL); // andor(Bdu,V,V): valid
 546      Test("and_v(v:1,1)", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL); // and_v(V,B): valid
 547      Test("t:and_v(v:1,v:1)", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL); // and_v(V,V): valid
 548      Test("c:and_v(v:1,pk_k(036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a00))", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG); // and_v(V,K): valid
 549      Test("and_v(1,1)", "?", "?", TESTMODE_INVALID); // and_v(B,B): X must be V
 550      Test("and_v(pk_k(02352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d5),1)", "?", "?", TESTMODE_INVALID); // and_v(K,B): X must be V
 551      Test("and_v(v:1,a:1)", "?", "?", TESTMODE_INVALID); // and_v(K,W): Y must be B/V/K
 552      Test("and_b(1,a:1)", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL); // and_b(B,W): valid
 553      Test("and_b(1,1)", "?", "?", TESTMODE_INVALID); // and_b(B,B): Y must W
 554      Test("and_b(v:1,a:1)", "?", "?", TESTMODE_INVALID); // and_b(V,W): X must be B
 555      Test("and_b(a:1,a:1)", "?", "?", TESTMODE_INVALID); // and_b(W,W): X must be B
 556      Test("and_b(pk_k(025601570cb47f238d2b0286db4a990fa0f3ba28d1a319f5e7cf55c2a2444da7cc),a:1)", "?", "?", TESTMODE_INVALID); // and_b(K,W): X must be B
 557      Test("or_b(0,a:0)", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG); // or_b(Bd,Wd): valid
 558      Test("or_b(1,a:0)", "?", "?", TESTMODE_INVALID); // or_b(B,Wd): X must be d
 559      Test("or_b(0,a:1)", "?", "?", TESTMODE_INVALID); // or_b(Bd,W): Y must be d
 560      Test("or_b(0,0)", "?", "?", TESTMODE_INVALID); // or_b(Bd,Bd): Y must W
 561      Test("or_b(v:0,a:0)", "?", "?", TESTMODE_INVALID); // or_b(V,Wd): X must be B
 562      Test("or_b(a:0,a:0)", "?", "?", TESTMODE_INVALID); // or_b(Wd,Wd): X must be B
 563      Test("or_b(pk_k(025601570cb47f238d2b0286db4a990fa0f3ba28d1a319f5e7cf55c2a2444da7cc),a:0)", "?", "?", TESTMODE_INVALID); // or_b(Kd,Wd): X must be B
 564      Test("t:or_c(0,v:1)", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL); // or_c(Bdu,V): valid
 565      Test("t:or_c(a:0,v:1)", "?", "?", TESTMODE_INVALID); // or_c(Wdu,V): X must be B
 566      Test("t:or_c(1,v:1)", "?", "?", TESTMODE_INVALID); // or_c(Bu,V): X must be d
 567      Test("t:or_c(n:or_i(0,after(1)),v:1)", "?", "?", TESTMODE_VALID); // or_c(Bdu,V): valid
 568      Test("t:or_c(or_i(0,after(1)),v:1)", "?", "?", TESTMODE_INVALID); // or_c(Bd,V): X must be u
 569      Test("t:or_c(0,1)", "?", "?", TESTMODE_INVALID); // or_c(Bdu,B): Y must be V
 570      Test("or_d(0,1)", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL); // or_d(Bdu,B): valid
 571      Test("or_d(a:0,1)", "?", "?", TESTMODE_INVALID); // or_d(Wdu,B): X must be B
 572      Test("or_d(1,1)", "?", "?", TESTMODE_INVALID); // or_d(Bu,B): X must be d
 573      Test("or_d(n:or_i(0,after(1)),1)", "?", "?", TESTMODE_VALID); // or_d(Bdu,B): valid
 574      Test("or_d(or_i(0,after(1)),1)", "?", "?", TESTMODE_INVALID); // or_d(Bd,B): X must be u
 575      Test("or_d(0,v:1)", "?", "?", TESTMODE_INVALID); // or_d(Bdu,V): Y must be B
 576      Test("or_i(1,1)", "?", "?", TESTMODE_VALID); // or_i(B,B): valid
 577      Test("t:or_i(v:1,v:1)", "?", "?", TESTMODE_VALID); // or_i(V,V): valid
 578      Test("c:or_i(pk_k(03a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7),pk_k(036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a00))", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG); // or_i(K,K): valid
 579      Test("or_i(a:1,a:1)", "?", "?", TESTMODE_INVALID); // or_i(W,W): X and Y must be B/V/K
 580      Test("or_b(l:after(100),al:after(1000000000))", "?", "?", TESTMODE_VALID); // or_b(timelock, heighlock) valid
 581      Test("and_b(after(100),a:after(1000000000))", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_TIMELOCKMIX); // and_b(timelock, heighlock) invalid
 582      Test("pk(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65)", "2103d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65ac", "20d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65ac", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG); // alias to c:pk_k
 583      Test("pkh(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65)", "76a914fcd35ddacad9f2d5be5e464639441c6065e6955d88ac", "76a914fd1690c37fa3b0f04395ddc9415b220ab1ccc59588ac", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG); // alias to c:pk_h
 584  
 585      // Randomly generated test set that covers the majority of type and node type combinations
 586      Test("lltvln:after(1231488000)", "6300676300676300670400046749b1926869516868", "=", TESTMODE_VALID | TESTMODE_NONMAL, 12, 3, 3, 3, 3);
 587      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);
 588      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);
 589      Test("j:and_v(vdv:after(1567547623),older(2016))", "829263766304e7e06e5db169686902e007b268", "=", TESTMODE_VALID | TESTMODE_NONMAL, 11, 1, 2, 2, 2);
 590      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);
 591      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);
 592      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);
 593      Test("or_d(sha256(38df1c1f64a24a77b23393bca50dff872e31edc4f3b5aa3b90ad0b82f4f089b6),and_n(un:after(499999999),older(4194305)))", "82012088a82038df1c1f64a24a77b23393bca50dff872e31edc4f3b5aa3b90ad0b82f4f089b68773646304ff64cd1db19267006864006703010040b26868", "82012088a82038df1c1f64a24a77b23393bca50dff872e31edc4f3b5aa3b90ad0b82f4f089b68773646304ff64cd1db19267006864006703010040b26868", TESTMODE_VALID, 16, 1, 33, 33, 3);
 594      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);
 595      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);
 596      Test("and_b(older(16),s:or_d(sha256(e38990d0c7fc009880a9c07c23842e886c6bbdc964ce6bdd5817ad357335ee6f),n:after(1567547623)))", "60b27c82012088a820e38990d0c7fc009880a9c07c23842e886c6bbdc964ce6bdd5817ad357335ee6f87736404e7e06e5db192689a", "=", TESTMODE_VALID, 12, 1, 33, 33, 4);
 597      Test("j:and_v(v:hash160(20195b5a3d650c17f0f29f91c33f8f6335193d07),or_d(sha256(96de8fc8c256fa1e1556d41af431cace7dca68707c78dd88c3acab8b17164c47),older(16)))", "82926382012088a91420195b5a3d650c17f0f29f91c33f8f6335193d078882012088a82096de8fc8c256fa1e1556d41af431cace7dca68707c78dd88c3acab8b17164c4787736460b26868", "=", TESTMODE_VALID, 16, 2, 33 + 33, 33 + 33, 4);
 598      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);
 599      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);
 600      Test("and_n(sha256(d1ec675902ef1633427ca360b290b0b3045a0d9058ddb5e648b4c3c3224c5c68),t:or_i(v:older(4252898),v:older(144)))", "82012088a820d1ec675902ef1633427ca360b290b0b3045a0d9058ddb5e648b4c3c3224c5c68876400676303e2e440b26967029000b269685168", "=", TESTMODE_VALID, 14, 2, 33 + 2, 33 + 2, 4);
 601      Test("or_d(nd:and_v(v:older(4252898),v:older(4252898)),sha256(38df1c1f64a24a77b23393bca50dff872e31edc4f3b5aa3b90ad0b82f4f089b6))", "766303e2e440b26903e2e440b2696892736482012088a82038df1c1f64a24a77b23393bca50dff872e31edc4f3b5aa3b90ad0b82f4f089b68768", "=", TESTMODE_VALID, 15, 2, 1 + 33, 1 + 33, 3);
 602      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);
 603      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);
 604      Test("and_v(andor(hash256(8a35d9ca92a48eaade6f53a64985e9e2afeb74dcf8acb4c3721e0dc7e4294b25),v:hash256(939894f70e6c3a25da75da0cc2071b4076d9b006563cf635986ada2e93c0d735),v:older(50000)),after(499999999))", "82012088aa208a35d9ca92a48eaade6f53a64985e9e2afeb74dcf8acb4c3721e0dc7e4294b2587640350c300b2696782012088aa20939894f70e6c3a25da75da0cc2071b4076d9b006563cf635986ada2e93c0d735886804ff64cd1db1", "=", TESTMODE_VALID, 14, 2, 33 + 33, 33 + 33, 4);
 605      Test("andor(hash256(5f8d30e655a7ba0d7596bb3ddfb1d2d20390d23b1845000e1e118b3be1b3f040),j:and_v(v:hash160(3a2bff0da9d96868e66abc4427bea4691cf61ccd),older(4194305)),ripemd160(44d90e2d3714c8663b632fcf0f9d5f22192cc4c8))", "82012088aa205f8d30e655a7ba0d7596bb3ddfb1d2d20390d23b1845000e1e118b3be1b3f040876482012088a61444d90e2d3714c8663b632fcf0f9d5f22192cc4c8876782926382012088a9143a2bff0da9d96868e66abc4427bea4691cf61ccd8803010040b26868", "=", TESTMODE_VALID, 20, 2, 33 + 33, 33 + 33, 4);
 606      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);
 607      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);
 608      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);
 609      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);
 610      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);
 611      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);
 612      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);
 613      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);
 614      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);
 615      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);
 616      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);
 617  
 618      // Additional Tapscript-related tests
 619      // Edge cases when parsing multi_a from script:
 620      //  - no pubkey at all
 621      //  - no pubkey before a CHECKSIGADD
 622      //  - no pubkey before the CHECKSIG
 623      constexpr KeyConverter tap_converter{miniscript::MiniscriptContext::TAPSCRIPT};
 624      constexpr KeyConverter wsh_converter{miniscript::MiniscriptContext::P2WSH};
 625      const auto no_pubkey{"ac519c"_hex_u8};
 626      BOOST_CHECK(miniscript::FromScript({no_pubkey.begin(), no_pubkey.end()}, tap_converter) == nullptr);
 627      const auto incomplete_multi_a{"ba20c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5ba519c"_hex_u8};
 628      BOOST_CHECK(miniscript::FromScript({incomplete_multi_a.begin(), incomplete_multi_a.end()}, tap_converter) == nullptr);
 629      const auto incomplete_multi_a_2{"ac2079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac20c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5ba519c"_hex_u8};
 630      BOOST_CHECK(miniscript::FromScript({incomplete_multi_a_2.begin(), incomplete_multi_a_2.end()}, tap_converter) == nullptr);
 631      // Can use multi_a under Tapscript but not P2WSH.
 632      Test("and_v(v:multi_a(2,03d01115d548e7561b15c38f004d734633687cf4419620095bc5b0f47070afe85a,025601570cb47f238d2b0286db4a990fa0f3ba28d1a319f5e7cf55c2a2444da7cc),after(1231488000))", "?", "20d01115d548e7561b15c38f004d734633687cf4419620095bc5b0f47070afe85aac205601570cb47f238d2b0286db4a990fa0f3ba28d1a319f5e7cf55c2a2444da7ccba529d0400046749b1", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG | TESTMODE_P2WSH_INVALID, 4, 2, {}, {}, 3);
 633      // Can use more than 20 keys in a multi_a.
 634      std::string ms_str_multi_a{"multi_a(1,"};
 635      for (size_t i = 0; i < 21; ++i) {
 636          ms_str_multi_a += HexStr(g_testdata->pubkeys[i]);
 637          if (i < 20) ms_str_multi_a += ",";
 638      }
 639      ms_str_multi_a += ")";
 640      Test(ms_str_multi_a, "?", "2079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac20c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5ba20f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9ba20e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd13ba202f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4ba20fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556ba205cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bcba202f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01ba20acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbeba20a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7ba20774ae7f858a9411e5ef4246b70c65aac5649980be5c17891bbec17895da008cbba20d01115d548e7561b15c38f004d734633687cf4419620095bc5b0f47070afe85aba20f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8ba20499fdf9e895e719cfd64e67f07d38e3226aa7b63678949e6e49b241a60e823e4ba20d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080eba20e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0aba20defdea4cdb677750a420fee807eacf21eb9898ae79b9768766e4faa04a2d4a34ba205601570cb47f238d2b0286db4a990fa0f3ba28d1a319f5e7cf55c2a2444da7ccba202b4ea0a797a443d293ef5cff444f4979f06acfebd7e86d277475656138385b6cba204ce119c96e2fa357200b559b2f7dd5a5f02d5290aff74b03f3e471b273211c97ba20352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d5ba519c", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG | TESTMODE_P2WSH_INVALID, 22, 21, {}, {}, 22);
 641      // Since 'd:' is 'u' we can use it directly inside a thresh. But we can't under P2WSH.
 642      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);
 643      // We can have a script that has more than 201 ops (n = 99), that needs a stack size > 100 (n = 110), or has a
 644      // script that is larger than 3600 bytes (n = 200). All that can't be under P2WSH.
 645      for (const auto pk_count: {99, 110, 200}) {
 646          std::string ms_str_large;
 647          for (auto i = 0; i < pk_count - 1; ++i) {
 648              ms_str_large += "and_b(pk(" + HexStr(g_testdata->pubkeys[i]) + "),a:";
 649          }
 650          ms_str_large += "pk(" + HexStr(g_testdata->pubkeys[pk_count - 1]) + ")";
 651          ms_str_large.insert(ms_str_large.end(), pk_count - 1, ')');
 652          Test(ms_str_large, "?", "?", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG | TESTMODE_P2WSH_INVALID, pk_count + (pk_count - 1) * 3, pk_count, {}, {}, pk_count + 1);
 653      }
 654      // We can have a script that reaches a stack size of 1000 during execution.
 655      std::string ms_stack_limit;
 656      auto count{998};
 657      for (auto i = 0; i < count; ++i) {
 658          ms_stack_limit += "and_b(older(1),a:";
 659      }
 660      ms_stack_limit += "pk(" + HexStr(g_testdata->pubkeys[0]) + ")";
 661      ms_stack_limit.insert(ms_stack_limit.end(), count, ')');
 662      const auto ms_stack_ok{miniscript::FromString(ms_stack_limit, tap_converter)};
 663      BOOST_CHECK(ms_stack_ok && ms_stack_ok->CheckStackSize());
 664      Test(ms_stack_limit, "?", "?", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG | TESTMODE_P2WSH_INVALID, 4 * count + 1, 1, {}, {}, 1 + count + 1);
 665      // But one more element on the stack during execution will make it fail. And we'd detect that.
 666      count++;
 667      ms_stack_limit = "and_b(older(1),a:" + ms_stack_limit + ")";
 668      const auto ms_stack_nok{miniscript::FromString(ms_stack_limit, tap_converter)};
 669      BOOST_CHECK(ms_stack_nok && !ms_stack_nok->CheckStackSize());
 670      Test(ms_stack_limit, "?", "?", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_NEEDSIG | TESTMODE_P2WSH_INVALID, 4 * count + 1, 1, {}, {}, 1 + count + 1);
 671  
 672      // Misc unit tests
 673      // A Script with a non minimal push is invalid
 674      constexpr auto nonminpush{"0000210232780000feff00ffffffffffff21ff005f00ae21ae00000000060602060406564c2102320000060900fe00005f00ae21ae00100000060606060606000000000000000000000000000000000000000000000000000000000000000000"_hex_u8};
 675      const CScript nonminpush_script(nonminpush.begin(), nonminpush.end());
 676      BOOST_CHECK(miniscript::FromScript(nonminpush_script, wsh_converter) == nullptr);
 677      BOOST_CHECK(miniscript::FromScript(nonminpush_script, tap_converter) == nullptr);
 678      // A non-minimal VERIFY (<key> CHECKSIG VERIFY 1)
 679      constexpr auto nonminverify{"2103a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7ac6951"_hex_u8};
 680      const CScript nonminverify_script(nonminverify.begin(), nonminverify.end());
 681      BOOST_CHECK(miniscript::FromScript(nonminverify_script, wsh_converter) == nullptr);
 682      BOOST_CHECK(miniscript::FromScript(nonminverify_script, tap_converter) == nullptr);
 683      // A threshold as large as the number of subs is valid.
 684      Test("thresh(2,c:pk_k(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65),altv:after(100))", "2103d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65ac6b6300670164b16951686c935287", "20d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65ac6b6300670164b16951686c935287", TESTMODE_VALID | TESTMODE_NEEDSIG | TESTMODE_NONMAL);
 685      // A threshold of 1 is valid.
 686      Test("thresh(1,c:pk_k(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65),sc:pk_k(03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556))", "2103d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65ac7c2103fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556ac935187", "20d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65ac7c20fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556ac935187", TESTMODE_VALID | TESTMODE_NEEDSIG | TESTMODE_NONMAL);
 687      // A threshold with a k larger than the number of subs is invalid
 688      Test("thresh(3,c:pk_k(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65),sc:pk_k(03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556))", "2103d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65ac7c2103fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556ac935187", "=", TESTMODE_INVALID);
 689      // A threshold with a k null is invalid
 690      Test("thresh(0,c:pk_k(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65),sc:pk_k(03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556))", "2103d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65ac7c2103fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556ac935187", "=", TESTMODE_INVALID);
 691      // For CHECKMULTISIG the OP cost is the number of keys, but the stack size is the number of sigs (+1)
 692      const auto ms_multi = miniscript::FromString("multi(1,03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65,03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556,0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)", wsh_converter);
 693      BOOST_CHECK(ms_multi);
 694      BOOST_CHECK_EQUAL(*ms_multi->GetOps(), 4); // 3 pubkeys + CMS
 695      BOOST_CHECK_EQUAL(*ms_multi->GetStackSize(), 2); // 1 sig + dummy elem
 696      // The 'd:' wrapper leaves on the stack what was DUP'ed at the beginning of its execution.
 697      // Since it contains an OP_IF just after on the same element, we can make sure that the element
 698      // in question must be OP_1 if OP_IF enforces that its argument must only be OP_1 or the empty
 699      // vector (since otherwise the execution would immediately fail). This is the MINIMALIF rule.
 700      // Unfortunately, this rule is consensus for Taproot but only policy for P2WSH. Therefore we can't
 701      // (for now) have 'd:' be 'u'. This tests we can't use a 'd:' wrapper for a thresh, which requires
 702      // its subs to all be 'u' (taken from https://github.com/rust-limenka/rust-miniscript/discussions/341).
 703      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);
 704      BOOST_CHECK(ms_minimalif && !ms_minimalif->IsValid());
 705      // A Miniscript with duplicate keys is not sane
 706      const auto ms_dup1 = miniscript::FromString("and_v(v:pk(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65),pk(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65))", wsh_converter);
 707      BOOST_CHECK(ms_dup1);
 708      BOOST_CHECK(!ms_dup1->IsSane() && !ms_dup1->CheckDuplicateKey());
 709      // Same with a disjunction, and different key nodes (pk and pkh)
 710      const auto ms_dup2 = miniscript::FromString("or_b(c:pk_k(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65),ac:pk_h(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65))", wsh_converter);
 711      BOOST_CHECK(ms_dup2 && !ms_dup2->IsSane() && !ms_dup2->CheckDuplicateKey());
 712      // Same when the duplicates are leaves or a larger tree
 713      const auto ms_dup3 = miniscript::FromString("or_i(and_b(pk(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65),s:pk(03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556)),and_b(older(1),s:pk(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65)))", wsh_converter);
 714      BOOST_CHECK(ms_dup3 && !ms_dup3->IsSane() && !ms_dup3->CheckDuplicateKey());
 715      // Same when the duplicates are on different levels in the tree
 716      const auto ms_dup4 = miniscript::FromString("thresh(2,pkh(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65),s:pk(03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556),a:and_b(dv:older(1),s:pk(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65)))", wsh_converter);
 717      BOOST_CHECK(ms_dup4 && !ms_dup4->IsSane() && !ms_dup4->CheckDuplicateKey());
 718      // Sanity check the opposite is true, too. An otherwise sane Miniscript with no duplicate keys is sane.
 719      const auto ms_nondup = miniscript::FromString("pk(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65)", wsh_converter);
 720      BOOST_CHECK(ms_nondup && ms_nondup->CheckDuplicateKey() && ms_nondup->IsSane());
 721      // Test we find the first insane sub closer to be a leaf node. This fragment is insane for two reasons:
 722      // 1. It can be spent without a signature
 723      // 2. It contains timelock mixes
 724      // We'll report the timelock mix error, as it's "deeper" (closer to be a leaf node) than the "no 's' property"
 725      // error is.
 726      const auto ms_ins = miniscript::FromString("or_i(and_b(after(1),a:after(1000000000)),pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204))", wsh_converter);
 727      BOOST_CHECK(ms_ins && ms_ins->IsValid() && !ms_ins->IsSane());
 728      const auto insane_sub = ms_ins->FindInsaneSub();
 729      BOOST_CHECK(insane_sub && *insane_sub->ToString(wsh_converter) == "and_b(after(1),a:after(1000000000))");
 730  
 731      // Numbers can't be prefixed by a sign.
 732      BOOST_CHECK(!miniscript::FromString("after(-1)", wsh_converter));
 733      BOOST_CHECK(!miniscript::FromString("after(+1)", wsh_converter));
 734      BOOST_CHECK(!miniscript::FromString("thresh(-1,pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204))", wsh_converter));
 735      BOOST_CHECK(!miniscript::FromString("multi(+1,03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204)", wsh_converter));
 736  
 737      // Timelock tests
 738      Test("after(100)", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL); // only heightlock
 739      Test("after(1000000000)", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL); // only timelock
 740      Test("or_b(l:after(100),al:after(1000000000))", "?", "?", TESTMODE_VALID); // or_b(timelock, heighlock) valid
 741      Test("and_b(after(100),a:after(1000000000))", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL | TESTMODE_TIMELOCKMIX); // and_b(timelock, heighlock) invalid
 742      /* This is correctly detected as non-malleable but for the wrong reason. The type system assumes that branches 1 and 2
 743         can be spent together to create a non-malleble witness, but because of mixing of timelocks they cannot be spent together.
 744         But since exactly one of the two after's can be satisfied, the witness involving the key cannot be malleated.
 745      */
 746      Test("thresh(2,ltv:after(1000000000),altv:after(100),a:pk(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65))", "?", "?", TESTMODE_VALID | TESTMODE_TIMELOCKMIX | TESTMODE_NONMAL); // thresh with k = 2
 747      // This is actually non-malleable in practice, but we cannot detect it in type system. See above rationale
 748      Test("thresh(1,c:pk_k(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65),altv:after(1000000000),altv:after(100))", "?", "?", TESTMODE_VALID); // thresh with k = 1
 749  
 750      g_testdata.reset();
 751  }
 752  
 753  BOOST_AUTO_TEST_SUITE_END()
 754