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