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}2502}2503return ret;2504} else if (multi || sortedmulti) {2505error = "Can only have multi/sortedmulti at top level, in sh(), or in wsh()";2506return {};2507} else if (multi_a || sortedmulti_a) {2508error = "Can only have multi_a/sortedmulti_a inside tr()";2509return {};2510}2511if ((ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH) && Func("wpkh", expr)) {2512auto pubkeys = ParsePubkey(key_exp_index, expr, ParseScriptContext::P2WPKH, out, error);2513if (pubkeys.empty()) {2514error = strprintf("wpkh(): %s", error);2515return {};2516}2517for (auto& pubkey : pubkeys) {2518ret.emplace_back(std::make_unique<WPKHDescriptor>(std::move(pubkey)));2519}2520return ret;2521} else if (Func("wpkh", expr)) {2522error = "Can only have wpkh() at top level or inside sh()";2523return {};2524}2525if (ctx == ParseScriptContext::TOP && Func("sh", expr)) {2526auto descs = ParseScript(key_exp_index, expr, ParseScriptContext::P2SH, out, error);2527if (descs.empty() || expr.size()) return {};2528std::vector<std::unique_ptr<DescriptorImpl>> ret;2529ret.reserve(descs.size());2530for (auto& desc : descs) {2531ret.push_back(std::make_unique<SHDescriptor>(std::move(desc)));2532}2533return ret;2534} else if (Func("sh", expr)) {2535error = "Can only have sh() at top level";2536return {};2537}2538if ((ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH) && Func("wsh", expr)) {2539auto descs = ParseScript(key_exp_index, expr, ParseScriptContext::P2WSH, out, error);2540if (descs.empty() || expr.size()) return {};2541for (auto& desc : descs) {2542ret.emplace_back(std::make_unique<WSHDescriptor>(std::move(desc)));2543}2544return ret;2545} else if (Func("wsh", expr)) {2546error = "Can only have wsh() at top level or inside sh()";2547return {};2548}2549if (ctx == ParseScriptContext::TOP && Func("addr", expr)) {2550CTxDestination dest = DecodeDestination(std::string(expr.begin(), expr.end()));2551if (!IsValidDestination(dest)) {2552error = "Address is not valid";2553return {};2554}2555ret.emplace_back(std::make_unique<AddressDescriptor>(std::move(dest)));2556return ret;2557} else if (Func("addr", expr)) {2558error = "Can only have addr() at top level";2559return {};2560}2561if (ctx == ParseScriptContext::TOP && Func("tr", expr)) {2562auto arg = Expr(expr);2563auto internal_keys = ParsePubkey(key_exp_index, arg, ParseScriptContext::P2TR, out, error);2564if (internal_keys.empty()) {2565error = strprintf("tr(): %s", error);2566return {};2567}2568size_t max_providers_len = internal_keys.size();2569std::vector<std::vector<std::unique_ptr<DescriptorImpl>>> subscripts; //!< list of multipath expanded script subexpressions2570std::vector<int> depths; //!< depth in the tree of each subexpression (same length subscripts)2571if (expr.size()) {2572if (!Const(",", expr)) {2573error = strprintf("tr: expected ',', got '%c'", expr[0]);2574return {};2575}2576/** The path from the top of the tree to what we're currently processing.2577* branches[i] == false: left branch in the i'th step from the top; true: right branch.2578*/2579std::vector<bool> branches;2580// Loop over all provided scripts. In every iteration exactly one script will be processed.2581// Use a do-loop because inside this if-branch we expect at least one script.2582do {2583// First process all open braces.2584while (Const("{", expr)) {2585branches.push_back(false); // new left branch2586if (branches.size() > TAPROOT_CONTROL_MAX_NODE_COUNT) {2587error = strprintf("tr() supports at most %i nesting levels", TAPROOT_CONTROL_MAX_NODE_COUNT);2588return {};2589}2590}2591// Process the actual script expression.2592auto sarg = Expr(expr);2593subscripts.emplace_back(ParseScript(key_exp_index, sarg, ParseScriptContext::P2TR, out, error));2594if (subscripts.back().empty()) return {};2595max_providers_len = std::max(max_providers_len, subscripts.back().size());2596depths.push_back(branches.size());2597// Process closing braces; one is expected for every right branch we were in.2598while (branches.size() && branches.back()) {2599if (!Const("}", expr)) {2600error = strprintf("tr(): expected '}' after script expression");2601return {};2602}2603branches.pop_back(); // move up one level after encountering '}'2604}2605// If after that, we're at the end of a left branch, expect a comma.2606if (branches.size() && !branches.back()) {2607if (!Const(",", expr)) {2608error = strprintf("tr(): expected ',' after script expression");2609return {};2610}2611branches.back() = true; // And now we're in a right branch.2612}2613} while (branches.size());2614// After we've explored a whole tree, we must be at the end of the expression.2615if (expr.size()) {2616error = strprintf("tr(): expected ')' after script expression");2617return {};2618}2619}2620assert(TaprootBuilder::ValidDepths(depths));2622// Make sure all vecs are of the same length, or exactly length 12623// For length 1 vectors, clone subdescs until vector is the same length2624for (auto& vec : subscripts) {2625if (vec.size() == 1) {2626for (size_t i = 1; i < max_providers_len; ++i) {2627vec.emplace_back(vec.at(0)->Clone());2628}2629} else if (vec.size() != max_providers_len) {2630error = strprintf("tr(): Multipath subscripts have mismatched lengths");2631return {};2632}2633}2635if (internal_keys.size() > 1 && internal_keys.size() != max_providers_len) {2636error = strprintf("tr(): Multipath internal key mismatches multipath subscripts lengths");2637return {};2638}2640while (internal_keys.size() < max_providers_len) {2641internal_keys.emplace_back(internal_keys.at(0)->Clone());2642}2644// Build the final descriptors vector2645for (size_t i = 0; i < max_providers_len; ++i) {2646// Build final subscripts vectors by retrieving the i'th subscript for each vector in subscripts2647std::vector<std::unique_ptr<DescriptorImpl>> this_subs;2648this_subs.reserve(subscripts.size());2649for (auto& subs : subscripts) {2650this_subs.emplace_back(std::move(subs.at(i)));2651}2652ret.emplace_back(std::make_unique<TRDescriptor>(std::move(internal_keys.at(i)), std::move(this_subs), depths));2653}2654return ret;2657} else if (Func("tr", expr)) {2658error = "Can only have tr at top level";2659return {};2660}2661if (ctx == ParseScriptContext::TOP && Func("rawtr", expr)) {2662auto arg = Expr(expr);2663if (expr.size()) {2664error = strprintf("rawtr(): only one key expected.");2665return {};2666}2667auto output_keys = ParsePubkey(key_exp_index, arg, ParseScriptContext::P2TR, out, error);2668if (output_keys.empty()) {2669error = strprintf("rawtr(): %s", error);2670return {};2671}2672for (auto& pubkey : output_keys) {2673ret.emplace_back(std::make_unique<RawTRDescriptor>(std::move(pubkey)));2674}2675return ret;2676} else if (Func("rawtr", expr)) {2677error = "Can only have rawtr at top level";2678return {};2679}2680if (ctx == ParseScriptContext::TOP && Func("unused", expr)) {2681// Check for only one expression, should not find commas, brackets, or parentheses2682auto arg = Expr(expr);2683if (expr.size()) {2684error = strprintf("unused(): only one key expected");2685return {};2686}2687auto keys = ParsePubkey(key_exp_index, arg, ctx, out, error);2688if (keys.empty()) return {};2689for (auto& pubkey : keys) {2690if (pubkey->IsRange()) {2691error = "unused(): key cannot be ranged";2692return {};2693}2694ret.emplace_back(std::make_unique<UnusedDescriptor>(std::move(pubkey)));2695}2696return ret;2697} else if (Func("unused", expr)) {2698error = "Can only have unused at top level";2699return {};2700}2701if (ctx == ParseScriptContext::TOP && Func("raw", expr)) {2702std::string str(expr.begin(), expr.end());2703if (!IsHex(str)) {2704error = "Raw script is not hex";2705return {};2706}2707auto bytes = ParseHex(str);2708ret.emplace_back(std::make_unique<RawDescriptor>(CScript(bytes.begin(), bytes.end())));2709return ret;2710} else if (Func("raw", expr)) {2711error = "Can only have raw() at top level";2712return {};2713}2714// Process miniscript expressions.2715{2716const auto script_ctx{ctx == ParseScriptContext::P2WSH ? miniscript::MiniscriptContext::P2WSH : miniscript::MiniscriptContext::TAPSCRIPT};2717KeyParser parser(/*out = */&out, /* in = */nullptr, /* ctx = */script_ctx, key_exp_index);2718auto node = miniscript::FromString(std::string(expr.begin(), expr.end()), parser);2719if (parser.m_key_parsing_error != "") {2720error = std::move(parser.m_key_parsing_error);2721return {};2722}2723if (node) {2724if (ctx != ParseScriptContext::P2WSH && ctx != ParseScriptContext::P2TR) {2725error = "Miniscript expressions can only be used in wsh or tr.";2726return {};2727}2728if (!node->IsSane() || node->IsNotSatisfiable()) {2729// Try to find the first insane sub for better error reporting.2730const auto* insane_node = &node.value();2731if (const auto sub = node->FindInsaneSub()) insane_node = sub;2732error = *insane_node->ToString(parser);2733if (!insane_node->IsValid()) {2734error += " is invalid";2735} else if (!node->IsSane()) {2736error += " is not sane";2737if (!insane_node->IsNonMalleable()) {2738error += ": malleable witnesses exist";2739} else if (insane_node == &node.value() && !insane_node->NeedsSignature()) {2740error += ": witnesses without signature exist";2741} else if (!insane_node->CheckTimeLocksMix()) {2742error += ": contains mixes of timelocks expressed in blocks and seconds";2743} else if (!insane_node->CheckDuplicateKey()) {2744error += ": contains duplicate public keys";2745} else if (!insane_node->ValidSatisfactions()) {2746error += ": needs witnesses that may exceed resource limits";2747}2748} else {2749error += " is not satisfiable";2750}