Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
251}252return "Bdu"_mst |253"z"_mst.If(args == 0) | // z=all z254"o"_mst.If(args == 1) | // o=all z except one o255"e"_mst.If(all_e && num_s == n_subs) | // e=all e and all s256"m"_mst.If(all_e && all_m && num_s >= n_subs - k) | // m=all e, >=(n-k) s257"s"_mst.If(num_s >= n_subs - k + 1) | // s= >=(n-k+1) s258acc_tl; // timelock info259}260}261assert(false);262}264size_t ComputeScriptLen(Fragment fragment, Type sub0typ, size_t subsize, uint32_t k, size_t n_subs,265size_t n_keys, MiniscriptContext ms_ctx) {266switch (fragment) {267case Fragment::JUST_1:268case Fragment::JUST_0: return 1;269case Fragment::PK_K: return IsTapscript(ms_ctx) ? 33 : 34;270case Fragment::PK_H: return 3 + 21;271case Fragment::OLDER:272case Fragment::AFTER: return 1 + BuildScript(k).size();273case Fragment::HASH256:274case Fragment::SHA256: return 4 + 2 + 33;275case Fragment::HASH160:276case Fragment::RIPEMD160: return 4 + 2 + 21;277case Fragment::MULTI: return 1 + BuildScript(n_keys).size() + BuildScript(k).size() + 34 * n_keys;278case Fragment::MULTI_A: return (1 + 32 + 1) * n_keys + BuildScript(k).size() + 1;279case Fragment::AND_V: return subsize;280case Fragment::WRAP_V: return subsize + (sub0typ << "x"_mst);281case Fragment::WRAP_S:282case Fragment::WRAP_C:283case Fragment::WRAP_N:284case Fragment::AND_B:285case Fragment::OR_B: return subsize + 1;286case Fragment::WRAP_A:287case Fragment::OR_C: return subsize + 2;288case Fragment::WRAP_D:289case Fragment::OR_D:290case Fragment::OR_I:291case Fragment::ANDOR: return subsize + 3;292case Fragment::WRAP_J: return subsize + 4;293case Fragment::THRESH: return subsize + n_subs + BuildScript(k).size();294}295assert(false);296}298InputStack& InputStack::SetAvailable(Availability avail) {299available = avail;300if (avail == Availability::NO) {301stack.clear();302size = std::numeric_limits<size_t>::max();303has_sig = false;304malleable = false;305non_canon = false;306}307return *this;308}310InputStack& InputStack::SetWithSig() {311has_sig = true;312return *this;313}315InputStack& InputStack::SetNonCanon() {316non_canon = true;317return *this;318}320InputStack& InputStack::SetMalleable(bool x) {321malleable = x;322return *this;323}325InputStack operator+(InputStack a, InputStack b) {326a.stack = Cat(std::move(a.stack), std::move(b.stack));327if (a.available != Availability::NO && b.available != Availability::NO) a.size += b.size;328a.has_sig |= b.has_sig;329a.malleable |= b.malleable;330a.non_canon |= b.non_canon;331if (a.available == Availability::NO || b.available == Availability::NO) {332a.SetAvailable(Availability::NO);333} else if (a.available == Availability::MAYBE || b.available == Availability::MAYBE) {334a.SetAvailable(Availability::MAYBE);335}336return a;337}339InputStack operator|(InputStack a, InputStack b) {340// If only one is invalid, pick the other one. If both are invalid, pick an arbitrary one.341if (a.available == Availability::NO) return b;342if (b.available == Availability::NO) return a;343// If only one of the solutions has a signature, we must pick the other one.344if (!a.has_sig && b.has_sig) return a;345if (!b.has_sig && a.has_sig) return b;346if (!a.has_sig && !b.has_sig) {347// If neither solution requires a signature, the result is inevitably malleable.348a.malleable = true;349b.malleable = true;350} else {351// If both options require a signature, prefer the non-malleable one.352if (b.malleable && !a.malleable) return a;353if (a.malleable && !b.malleable) return b;354}355// Between two malleable or two non-malleable solutions, pick the smaller one between356// YESes, and the bigger ones between MAYBEs. Prefer YES over MAYBE.357if (a.available == Availability::YES && b.available == Availability::YES) {358return std::move(a.size <= b.size ? a : b);359} else if (a.available == Availability::MAYBE && b.available == Availability::MAYBE) {360return std::move(a.size >= b.size ? a : b);361} else if (a.available == Availability::YES) {362return a;363} else {364return b;365}366}368std::optional<std::vector<Opcode>> DecomposeScript(const CScript& script)369{370std::vector<Opcode> out;371CScript::const_iterator it = script.begin(), itend = script.end();372while (it != itend) {373std::vector<unsigned char> push_data;374opcodetype opcode;375if (!script.GetOp(it, opcode, push_data)) {376return {};377} else if (opcode >= OP_1 && opcode <= OP_16) {378// Deal with OP_n (GetOp does not turn them into pushes).379push_data.assign(1, CScript::DecodeOP_N(opcode));380} else if (opcode == OP_CHECKSIGVERIFY) {381// Decompose OP_CHECKSIGVERIFY into OP_CHECKSIG OP_VERIFY382out.emplace_back(OP_CHECKSIG, std::vector<unsigned char>());383opcode = OP_VERIFY;384} else if (opcode == OP_CHECKMULTISIGVERIFY) {385// Decompose OP_CHECKMULTISIGVERIFY into OP_CHECKMULTISIG OP_VERIFY386out.emplace_back(OP_CHECKMULTISIG, std::vector<unsigned char>());387opcode = OP_VERIFY;388} else if (opcode == OP_EQUALVERIFY) {389// Decompose OP_EQUALVERIFY into OP_EQUAL OP_VERIFY390out.emplace_back(OP_EQUAL, std::vector<unsigned char>());391opcode = OP_VERIFY;392} else if (opcode == OP_NUMEQUALVERIFY) {393// Decompose OP_NUMEQUALVERIFY into OP_NUMEQUAL OP_VERIFY394out.emplace_back(OP_NUMEQUAL, std::vector<unsigned char>());395opcode = OP_VERIFY;396} else if (IsPushdataOp(opcode)) {397if (!CheckMinimalPush(push_data, opcode)) return {};398} else if (it != itend && (opcode == OP_CHECKSIG || opcode == OP_CHECKMULTISIG || opcode == OP_EQUAL || opcode == OP_NUMEQUAL) && (*it == OP_VERIFY)) {399// Rule out non minimal VERIFY sequences400return {};401}402out.emplace_back(opcode, std::move(push_data));403}404std::reverse(out.begin(), out.end());405return out;406}408std::optional<int64_t> ParseScriptNumber(const Opcode& in) {409if (in.first == OP_0) {410return 0;411}412if (!in.second.empty()) {413if (IsPushdataOp(in.first) && !CheckMinimalPush(in.second, in.first)) return {};414try {415return CScriptNum(in.second, true).GetInt64();416} catch(const scriptnum_error&) {}417}418return {};419}421int FindNextChar(std::span<const char> sp, const char m)422{423for (int i = 0; i < (int)sp.size(); ++i) {424if (sp[i] == m) return i;425// We only search within the current parentheses426if (sp[i] == ')') break;427}428return -1;429}431} // namespace internal432} // namespace miniscript
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.