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.
2001constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_H, Vector(std::move(*key)));2002script_size += 23;2003} else if (Const("sha256(", in, /*skip=*/false)) {2004std::optional<std::vector<unsigned char>> hash = ParseHexStr("sha256", in, 32);2005if (!hash) return {};2006constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, std::move(*hash));2007script_size += 38;2008} else if (Const("ripemd160(", in, /*skip=*/false)) {2009std::optional<std::vector<unsigned char>> hash = ParseHexStr("ripemd160", in, 20);2010if (!hash) return {};2011constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::RIPEMD160, std::move(*hash));2012script_size += 26;2013} else if (Const("hash256(", in, /*skip=*/false)) {2014std::optional<std::vector<unsigned char>> hash = ParseHexStr("hash256", in, 32);2015if (!hash) return {};2016constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, std::move(*hash));2017script_size += 38;2018} else if (Const("hash160(", in, /*skip=*/false)) {2019std::optional<std::vector<unsigned char>> hash = ParseHexStr("hash160", in, 20);2020if (!hash) return {};2021constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, std::move(*hash));2022script_size += 26;2023} else if (Const("after(", in, /*skip=*/false)) {2024auto expr = Expr(in);2025if (!Func("after", expr)) return {};2026const auto num{ToIntegral<int64_t>(std::string_view(expr.begin(), expr.end()))};2027if (!num.has_value() || *num < 1 || *num >= 0x80000000L) return {};2028constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num);2029script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);2030} else if (Const("older(", in, /*skip=*/false)) {2031auto expr = Expr(in);2032if (!Func("older", expr)) return {};2033const auto num{ToIntegral<int64_t>(std::string_view(expr.begin(), expr.end()))};2034if (!num.has_value() || *num < 1 || *num >= 0x80000000L) return {};2035constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num);2036script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);2037} else if (Const("multi(", in)) {2038if (!parse_multi_exp(in, /* is_multi_a = */false)) return {};2039} else if (Const("multi_a(", in)) {2040if (!parse_multi_exp(in, /* is_multi_a = */true)) return {};2041} else if (Const("thresh(", in)) {2042int next_comma = FindNextChar(in, ',');2043if (next_comma < 1) return {};2044const auto k{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};2045if (!k.has_value() || *k < 1) return {};2046in = in.subspan(next_comma + 1);2047// n = 1 here because we read the first WRAPPED_EXPR before reaching THRESH2048to_parse.emplace_back(ParseContext::THRESH, 1, *k);2049to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);2050script_size += 2 + (*k > 16) + (*k > 0x7f) + (*k > 0x7fff) + (*k > 0x7fffff);2051} else if (Const("andor(", in)) {2052to_parse.emplace_back(ParseContext::ANDOR, -1, -1);2053to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);2054to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);2055to_parse.emplace_back(ParseContext::COMMA, -1, -1);2056to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);2057to_parse.emplace_back(ParseContext::COMMA, -1, -1);2058to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);2059script_size += 5;2060} else {2061if (Const("and_n(", in)) {2062to_parse.emplace_back(ParseContext::AND_N, -1, -1);2063script_size += 5;2064} else if (Const("and_b(", in)) {2065to_parse.emplace_back(ParseContext::AND_B, -1, -1);2066script_size += 2;2067} else if (Const("and_v(", in)) {2068to_parse.emplace_back(ParseContext::AND_V, -1, -1);2069script_size += 1;2070} else if (Const("or_b(", in)) {2071to_parse.emplace_back(ParseContext::OR_B, -1, -1);2072script_size += 2;2073} else if (Const("or_c(", in)) {2074to_parse.emplace_back(ParseContext::OR_C, -1, -1);2075script_size += 3;2076} else if (Const("or_d(", in)) {2077to_parse.emplace_back(ParseContext::OR_D, -1, -1);2078script_size += 4;2079} else if (Const("or_i(", in)) {2080to_parse.emplace_back(ParseContext::OR_I, -1, -1);2081script_size += 4;2082} else {2083return {};2084}2085to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);2086to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);2087to_parse.emplace_back(ParseContext::COMMA, -1, -1);2088to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);2089}2090break;2091}2092case ParseContext::ALT: {2093constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A, Vector(std::move(constructed.back()))};2094break;2095}2096case ParseContext::SWAP: {2097constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S, Vector(std::move(constructed.back()))};2098break;2099}2100case ParseContext::CHECK: {2101constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C, Vector(std::move(constructed.back()))};2102break;2103}2104case ParseContext::DUP_IF: {2105constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D, Vector(std::move(constructed.back()))};2106break;2107}2108case ParseContext::NON_ZERO: {2109constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J, Vector(std::move(constructed.back()))};2110break;2111}2112case ParseContext::ZERO_NOTEQUAL: {2113constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N, Vector(std::move(constructed.back()))};2114break;2115}2116case ParseContext::VERIFY: {2117script_size += (constructed.back().GetType() << "x"_mst);2118constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V, Vector(std::move(constructed.back()))};2119break;2120}2121case ParseContext::WRAP_U: {2122constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::OR_I, Vector(std::move(constructed.back()), Node<Key>{internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0})};2123break;2124}2125case ParseContext::WRAP_T: {2126constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::AND_V, Vector(std::move(constructed.back()), Node<Key>{internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1})};2127break;2128}2129case ParseContext::AND_B: {2130BuildBack(ctx.MsContext(), Fragment::AND_B, constructed);2131break;2132}2133case ParseContext::AND_N: {2134auto mid = std::move(constructed.back());2135constructed.pop_back();2136constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR, Vector(std::move(constructed.back()), std::move(mid), Node<Key>{internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0})};2137break;2138}2139case ParseContext::AND_V: {2140BuildBack(ctx.MsContext(), Fragment::AND_V, constructed);2141break;2142}2143case ParseContext::OR_B: {2144BuildBack(ctx.MsContext(), Fragment::OR_B, constructed);2145break;2146}2147case ParseContext::OR_C: {2148BuildBack(ctx.MsContext(), Fragment::OR_C, constructed);2149break;2150}2151case ParseContext::OR_D: {2152BuildBack(ctx.MsContext(), Fragment::OR_D, constructed);2153break;2154}2155case ParseContext::OR_I: {2156BuildBack(ctx.MsContext(), Fragment::OR_I, constructed);2157break;2158}2159case ParseContext::ANDOR: {2160auto right = std::move(constructed.back());2161constructed.pop_back();2162auto mid = std::move(constructed.back());2163constructed.pop_back();2164constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR, Vector(std::move(constructed.back()), std::move(mid), std::move(right))};2165break;2166}2167case ParseContext::THRESH: {2168if (in.size() < 1) return {};2169if (in[0] == ',') {2170in = in.subspan(1);2171to_parse.emplace_back(ParseContext::THRESH, n+1, k);2172to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);2173script_size += 2;2174} else if (in[0] == ')') {2175if (k > n) return {};2176in = in.subspan(1);2177// Children are constructed in reverse order, so iterate from end to beginning2178std::vector<Node<Key>> subs;2179for (int i = 0; i < n; ++i) {2180subs.push_back(std::move(constructed.back()));2181constructed.pop_back();2182}2183std::reverse(subs.begin(), subs.end());2184constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs), k);2185} else {2186return {};2187}2188break;2189}2190case ParseContext::COMMA: {2191if (in.size() < 1 || in[0] != ',') return {};2192in = in.subspan(1);2193break;2194}2195case ParseContext::CLOSE_BRACKET: {2196if (in.size() < 1 || in[0] != ')') return {};2197in = in.subspan(1);2198break;2199}2200}2201}2203// Sanity checks on the produced miniscript2204assert(constructed.size() >= 1);2205CHECK_NONFATAL(constructed.size() == 1);2206assert(constructed[0].ScriptSize() == script_size);2207if (in.size() > 0) return {};2208Node<Key> tl_node{std::move(constructed.front())};2209tl_node.DuplicateKeyCheck(ctx);2210return tl_node;2211}2213/** Decode a script into opcode/push pairs.2214*2215* Construct a vector with one element per opcode in the script, in reverse order.2216* Each element is a pair consisting of the opcode, as well as the data pushed by2217* the opcode (including OP_n), if any. OP_CHECKSIGVERIFY, OP_CHECKMULTISIGVERIFY,2218* OP_NUMEQUALVERIFY and OP_EQUALVERIFY are decomposed into OP_CHECKSIG, OP_CHECKMULTISIG,2219* OP_EQUAL and OP_NUMEQUAL respectively, plus OP_VERIFY.2220*/2221std::optional<std::vector<Opcode>> DecomposeScript(const CScript& script);2223/** Determine whether the passed pair (created by DecomposeScript) is pushing a number. */2224std::optional<int64_t> ParseScriptNumber(const Opcode& in);2226enum class DecodeContext {2227/** A single expression of type B, K, or V. Specifically, this can't be an2228* and_v or an expression of type W (a: and s: wrappers). */2229SINGLE_BKV_EXPR,2230/** Potentially multiple SINGLE_BKV_EXPRs as children of (potentially multiple)2231* and_v expressions. Syntactic sugar for MAYBE_AND_V + SINGLE_BKV_EXPR. */2232BKV_EXPR,2233/** An expression of type W (a: or s: wrappers). */2234W_EXPR,2236/** SWAP expects the next element to be OP_SWAP (inside a W-type expression that2237* didn't end with FROMALTSTACK), and wraps the top of the constructed stack2238* with s: */2239SWAP,2240/** ALT expects the next element to be TOALTSTACK (we must have already read a2241* FROMALTSTACK earlier), and wraps the top of the constructed stack with a: */2242ALT,2243/** CHECK wraps the top constructed node with c: */2244CHECK,2245/** DUP_IF wraps the top constructed node with d: */2246DUP_IF,2247/** VERIFY wraps the top constructed node with v: */2248VERIFY,2249/** NON_ZERO wraps the top constructed node with j: */2250NON_ZERO,
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.