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.
2501} else {2502to_parse.emplace_back(DecodeContext::SWAP, -1, -1);2503}2504to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);2505break;2506}2507case DecodeContext::MAYBE_AND_V: {2508// If we reach a potential AND_V top-level, check if the next part of the script could be another AND_V child2509// These op-codes cannot end any well-formed miniscript so cannot be used in an and_v node.2510if (in < last && in[0].first != OP_IF && in[0].first != OP_ELSE && in[0].first != OP_NOTIF && in[0].first != OP_TOALTSTACK && in[0].first != OP_SWAP) {2511to_parse.emplace_back(DecodeContext::AND_V, -1, -1);2512// BKV_EXPR can contain more AND_V nodes2513to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);2514}2515break;2516}2517case DecodeContext::SWAP: {2518if (in >= last || in[0].first != OP_SWAP || constructed.empty()) return {};2519++in;2520constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S, Vector(std::move(constructed.back()))};2521break;2522}2523case DecodeContext::ALT: {2524if (in >= last || in[0].first != OP_TOALTSTACK || constructed.empty()) return {};2525++in;2526constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A, Vector(std::move(constructed.back()))};2527break;2528}2529case DecodeContext::CHECK: {2530if (constructed.empty()) return {};2531constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(std::move(constructed.back()))};2532break;2533}2534case DecodeContext::DUP_IF: {2535if (constructed.empty()) return {};2536constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D, Vector(std::move(constructed.back()))};2537break;2538}2539case DecodeContext::VERIFY: {2540if (constructed.empty()) return {};2541constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V, Vector(std::move(constructed.back()))};2542break;2543}2544case DecodeContext::NON_ZERO: {2545if (constructed.empty()) return {};2546constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J, Vector(std::move(constructed.back()))};2547break;2548}2549case DecodeContext::ZERO_NOTEQUAL: {2550if (constructed.empty()) return {};2551constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N, Vector(std::move(constructed.back()))};2552break;2553}2554case DecodeContext::AND_V: {2555if (constructed.size() < 2) return {};2556BuildBack(ctx.MsContext(), Fragment::AND_V, constructed, /*reverse=*/true);2557break;2558}2559case DecodeContext::AND_B: {2560if (constructed.size() < 2) return {};2561BuildBack(ctx.MsContext(), Fragment::AND_B, constructed, /*reverse=*/true);2562break;2563}2564case DecodeContext::OR_B: {2565if (constructed.size() < 2) return {};2566BuildBack(ctx.MsContext(), Fragment::OR_B, constructed, /*reverse=*/true);2567break;2568}2569case DecodeContext::OR_C: {2570if (constructed.size() < 2) return {};2571BuildBack(ctx.MsContext(), Fragment::OR_C, constructed, /*reverse=*/true);2572break;2573}2574case DecodeContext::OR_D: {2575if (constructed.size() < 2) return {};2576BuildBack(ctx.MsContext(), Fragment::OR_D, constructed, /*reverse=*/true);2577break;2578}2579case DecodeContext::ANDOR: {2580if (constructed.size() < 3) return {};2581Node left{std::move(constructed.back())};2582constructed.pop_back();2583Node right{std::move(constructed.back())};2584constructed.pop_back();2585Node mid{std::move(constructed.back())};2586constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR, Vector(std::move(left), std::move(mid), std::move(right))};2587break;2588}2589case DecodeContext::THRESH_W: {2590if (in >= last) return {};2591if (in[0].first == OP_ADD) {2592++in;2593to_parse.emplace_back(DecodeContext::THRESH_W, n+1, k);2594to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);2595} else {2596to_parse.emplace_back(DecodeContext::THRESH_E, n+1, k);2597// All children of thresh have type modifier d, so cannot be and_v2598to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);2599}2600break;2601}2602case DecodeContext::THRESH_E: {2603if (k < 1 || k > n || constructed.size() < static_cast<size_t>(n)) return {};2604std::vector<Node<Key>> subs;2605for (int i = 0; i < n; ++i) {2606Node sub{std::move(constructed.back())};2607constructed.pop_back();2608subs.push_back(std::move(sub));2609}2610constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs), k);2611break;2612}2613case DecodeContext::ENDIF: {2614if (in >= last) return {};2616// could be andor or or_i2617if (in[0].first == OP_ELSE) {2618++in;2619to_parse.emplace_back(DecodeContext::ENDIF_ELSE, -1, -1);2620to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);2621}2622// could be j: or d: wrapper2623else if (in[0].first == OP_IF) {2624if (last - in >= 2 && in[1].first == OP_DUP) {2625in += 2;2626to_parse.emplace_back(DecodeContext::DUP_IF, -1, -1);2627} else if (last - in >= 3 && in[1].first == OP_0NOTEQUAL && in[2].first == OP_SIZE) {2628in += 3;2629to_parse.emplace_back(DecodeContext::NON_ZERO, -1, -1);2630}2631else {2632return {};2633}2634// could be or_c or or_d2635} else if (in[0].first == OP_NOTIF) {2636++in;2637to_parse.emplace_back(DecodeContext::ENDIF_NOTIF, -1, -1);2638}2639else {2640return {};2641}2642break;2643}2644case DecodeContext::ENDIF_NOTIF: {2645if (in >= last) return {};2646if (in[0].first == OP_IFDUP) {2647++in;2648to_parse.emplace_back(DecodeContext::OR_D, -1, -1);2649} else {2650to_parse.emplace_back(DecodeContext::OR_C, -1, -1);2651}2652// or_c and or_d both require X to have type modifier d so, can't contain and_v2653to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);2654break;2655}2656case DecodeContext::ENDIF_ELSE: {2657if (in >= last) return {};2658if (in[0].first == OP_IF) {2659++in;2660BuildBack(ctx.MsContext(), Fragment::OR_I, constructed, /*reverse=*/true);2661} else if (in[0].first == OP_NOTIF) {2662++in;2663to_parse.emplace_back(DecodeContext::ANDOR, -1, -1);2664// andor requires X to have type modifier d, so it can't be and_v2665to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);2666} else {2667return {};2668}2669break;2670}2671}2672}2673if (constructed.size() != 1) return {};2674Node tl_node{std::move(constructed.front())};2675tl_node.DuplicateKeyCheck(ctx);2676// Note that due to how ComputeType works (only assign the type to the node if the2677// subs' types are valid) this would fail if any node of tree is badly typed.2678if (!tl_node.IsValidTopLevel()) return {};2679return tl_node;2680}2682} // namespace internal2684template <typename Ctx>2685inline std::optional<Node<typename Ctx::Key>> FromString(const std::string& str, const Ctx& ctx)2686{2687return internal::Parse<typename Ctx::Key>(str, ctx);2688}2690template <typename Ctx>2691inline std::optional<Node<typename Ctx::Key>> FromScript(const CScript& script, const Ctx& ctx)2692{2693using namespace internal;2694// A too large Script is necessarily invalid, don't bother parsing it.2695if (script.size() > MaxScriptSize(ctx.MsContext())) return {};2696auto decomposed = DecomposeScript(script);2697if (!decomposed) return {};2698auto it = decomposed->begin();2699auto ret = DecodeScript<typename Ctx::Key>(it, decomposed->end(), ctx);2700if (!ret) return {};2701if (it != decomposed->end()) return {};2702return ret;2703}2705} // namespace miniscript2707#endif // BITCOIN_SCRIPT_MINISCRIPT_H
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.