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.
501static constexpr SatInfo OP_SIZE() noexcept { return {-1, 0}; }502static constexpr SatInfo OP_CHECKSIG() noexcept { return {1, 1}; }503static constexpr SatInfo OP_0NOTEQUAL() noexcept { return {0, 0}; }504static constexpr SatInfo OP_VERIFY() noexcept { return {1, 1}; }505};507class StackSize508{509SatInfo sat, dsat;511public:512constexpr StackSize(SatInfo in_sat, SatInfo in_dsat) noexcept : sat(in_sat), dsat(in_dsat) {};513constexpr StackSize(SatInfo in_both) noexcept : sat(in_both), dsat(in_both) {};515const SatInfo& Sat() const { return sat; }516const SatInfo& Dsat() const { return dsat; }517};519struct WitnessSize {520//! Maximum witness size to satisfy;521MaxInt<uint32_t> sat;522//! Maximum witness size to dissatisfy;523MaxInt<uint32_t> dsat;525WitnessSize(MaxInt<uint32_t> in_sat, MaxInt<uint32_t> in_dsat) : sat(in_sat), dsat(in_dsat) {};526};528struct NoDupCheck {};530} // namespace internal532//! A node in a miniscript expression.533template <typename Key>534class Node535{536//! What node type this node is.537enum Fragment fragment;538//! The k parameter (time for OLDER/AFTER, threshold for THRESH(_M))539uint32_t k = 0;540//! The keys used by this expression (only for PK_K/PK_H/MULTI)541std::vector<Key> keys;542//! The data bytes in this expression (only for HASH160/HASH256/SHA256/RIPEMD160).543std::vector<unsigned char> data;544//! Subexpressions (for WRAP_*/AND_*/OR_*/ANDOR/THRESH)545std::vector<Node> subs;546//! The Script context for this node. Either P2WSH or Tapscript.547MiniscriptContext m_script_ctx;549public:550// Permit 1 level deep recursion since we own instances of our own type.551// NOLINTBEGIN(misc-no-recursion)552~Node()553{554// Destroy the subexpressions iteratively after moving out their555// subexpressions to avoid a stack-overflow due to recursive calls to556// the subs' destructors.557// We move vectors in order to only update array-pointers inside them558// rather than moving individual Node instances which would involve559// moving/copying each Node field.560std::vector<std::vector<Node>> queue;561queue.push_back(std::move(subs));562do {563auto flattening{std::move(queue.back())};564queue.pop_back();565for (Node& n : flattening) {566if (!n.subs.empty()) queue.push_back(std::move(n.subs));567}568} while (!queue.empty());569}570// NOLINTEND(misc-no-recursion)572Node<Key> Clone() const573{574// Use TreeEval() to avoid a stack-overflow due to recursion575auto upfn = [](const Node& node, std::span<Node> children) {576std::vector<Node> new_subs;577for (auto& child : children) {578// It's fine to move from children as they are new nodes having579// been produced by calling this function one level down.580new_subs.push_back(std::move(child));581}582return Node{internal::NoDupCheck{}, node.m_script_ctx, node.fragment, std::move(new_subs), node.keys, node.data, node.k};583};584return TreeEval<Node>(upfn);585}587enum Fragment Fragment() const { return fragment; }588uint32_t K() const { return k; }589const std::vector<Key>& Keys() const { return keys; }590const std::vector<unsigned char>& Data() const { return data; }591const std::vector<Node>& Subs() const { return subs; }593private:594//! Cached ops counts.595internal::Ops ops;596//! Cached stack size bounds.597internal::StackSize ss;598//! Cached witness size bounds.599internal::WitnessSize ws;600//! Cached expression type (computed by CalcType and fed through SanitizeType).601Type typ;602//! Cached script length (computed by CalcScriptLen).603size_t scriptlen;604//! Whether a public key appears more than once in this node. This value is initialized605//! by all constructors except the NoDupCheck ones. The NoDupCheck ones skip the606//! computation, requiring it to be done manually by invoking DuplicateKeyCheck().607//! DuplicateKeyCheck(), or a non-NoDupCheck constructor, will compute has_duplicate_keys608//! for all subnodes as well.609mutable std::optional<bool> has_duplicate_keys;611// Constructor which takes all of the data that a Node could possibly contain.612// This is kept private as no valid fragment has all of these arguments.613// Only used by Clone()614Node(internal::NoDupCheck, MiniscriptContext script_ctx, enum Fragment nt, std::vector<Node> sub, std::vector<Key> key, std::vector<unsigned char> arg, uint32_t val)615: fragment(nt), k(val), keys(std::move(key)), data(std::move(arg)), subs(std::move(sub)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}617//! Compute the length of the script for this miniscript (including children).618size_t CalcScriptLen() const619{620size_t subsize = 0;621for (const auto& sub : subs) {622subsize += sub.ScriptSize();623}624Type sub0type = subs.size() > 0 ? subs[0].GetType() : ""_mst;625return internal::ComputeScriptLen(fragment, sub0type, subsize, k, subs.size(), keys.size(), m_script_ctx);626}628/* Apply a recursive algorithm to a Miniscript tree, without actual recursive calls.629*630* The algorithm is defined by two functions: downfn and upfn. Conceptually, the631* result can be thought of as first using downfn to compute a "state" for each node,632* from the root down to the leaves. Then upfn is used to compute a "result" for each633* node, from the leaves back up to the root, which is then returned. In the actual634* implementation, both functions are invoked in an interleaved fashion, performing a635* depth-first traversal of the tree.636*637* In more detail, it is invoked as node.TreeEvalMaybe<Result>(root, downfn, upfn):638* - root is the state of the root node, of type State.639* - downfn is a callable (State&, const Node&, size_t) -> State, which given a640* node, its state, and an index of one of its children, computes the state of that641* child. It can modify the state. Children of a given node will have downfn()642* called in order.643* - upfn is a callable (State&&, const Node&, std::span<Result>) -> std::optional<Result>,644* which given a node, its state, and a span of the results of its children,645* computes the result of the node. If std::nullopt is returned by upfn,646* TreeEvalMaybe() immediately returns std::nullopt.647* The return value of TreeEvalMaybe is the result of the root node.648*649* Result type cannot be bool due to the std::vector<bool> specialization.650*/651template<typename Result, typename State, typename DownFn, typename UpFn>652std::optional<Result> TreeEvalMaybe(State root_state, DownFn downfn, UpFn upfn) const653{654/** Entries of the explicit stack tracked in this algorithm. */655struct StackElem656{657const Node& node; //!< The node being evaluated.658size_t expanded; //!< How many children of this node have been expanded.659State state; //!< The state for that node.661StackElem(const Node& node_, size_t exp_, State&& state_) :662node(node_), expanded(exp_), state(std::move(state_)) {}663};664/* Stack of tree nodes being explored. */665std::vector<StackElem> stack;666/* Results of subtrees so far. Their order and mapping to tree nodes667* is implicitly defined by stack. */668std::vector<Result> results;669stack.emplace_back(*this, 0, std::move(root_state));671/* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).672* State variables are omitted for simplicity.673*674* First: stack=[(A,0)] results=[]675* stack=[(A,1),(B,0)] results=[]676* stack=[(A,1)] results=[B]677* stack=[(A,2),(C,0)] results=[B]678* stack=[(A,2),(C,1),(D,0)] results=[B]679* stack=[(A,2),(C,1)] results=[B,D]680* stack=[(A,2),(C,2),(E,0)] results=[B,D]681* stack=[(A,2),(C,2)] results=[B,D,E]682* stack=[(A,2)] results=[B,C]683* stack=[(A,3),(F,0)] results=[B,C]684* stack=[(A,3)] results=[B,C,F]685* Final: stack=[] results=[A]686*/687while (stack.size()) {688const Node& node = stack.back().node;689if (stack.back().expanded < node.subs.size()) {690/* We encounter a tree node with at least one unexpanded child.691* Expand it. By the time we hit this node again, the result of692* that child (and all earlier children) will be at the end of `results`. */693size_t child_index = stack.back().expanded++;694State child_state = downfn(stack.back().state, node, child_index);695stack.emplace_back(node.subs[child_index], 0, std::move(child_state));696continue;697}698// Invoke upfn with the last node.subs.size() elements of results as input.699assert(results.size() >= node.subs.size());700std::optional<Result> result{upfn(std::move(stack.back().state), node,701std::span<Result>{results}.last(node.subs.size()))};702// If evaluation returns std::nullopt, abort immediately.703if (!result) return {};704// Replace the last node.subs.size() elements of results with the new result.705results.erase(results.end() - node.subs.size(), results.end());706results.push_back(std::move(*result));707stack.pop_back();708}709// The final remaining results element is the root result, return it.710assert(results.size() >= 1);711CHECK_NONFATAL(results.size() == 1);712return std::move(results[0]);713}715/** Like TreeEvalMaybe, but without downfn or State type.716* upfn takes (const Node&, std::span<Result>) and returns std::optional<Result>. */717template<typename Result, typename UpFn>718std::optional<Result> TreeEvalMaybe(UpFn upfn) const719{720struct DummyState {};721return TreeEvalMaybe<Result>(DummyState{},722[](DummyState, const Node&, size_t) { return DummyState{}; },723[&upfn](DummyState, const Node& node, std::span<Result> subs) {724return upfn(node, subs);725}726);727}729/** Like TreeEvalMaybe, but always produces a result. upfn must return Result. */730template<typename Result, typename State, typename DownFn, typename UpFn>731Result TreeEval(State root_state, DownFn&& downfn, UpFn upfn) const732{733// Invoke TreeEvalMaybe with upfn wrapped to return std::optional<Result>, and then734// unconditionally dereference the result (it cannot be std::nullopt).735return std::move(*TreeEvalMaybe<Result>(std::move(root_state),736std::forward<DownFn>(downfn),737[&upfn](State&& state, const Node& node, std::span<Result> subs) {738Result res{upfn(std::move(state), node, subs)};739return std::optional<Result>(std::move(res));740}741));742}744/** Like TreeEval, but without downfn or State type.745* upfn takes (const Node&, std::span<Result>) and returns Result. */746template<typename Result, typename UpFn>747Result TreeEval(UpFn upfn) const748{749struct DummyState {};750return std::move(*TreeEvalMaybe<Result>(DummyState{},
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.