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()