diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index 5026470edcf..f0294df72a9 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -1360,7 +1360,7 @@ public: for (const auto& arg : m_pubkey_args) { providers.push_back(arg->Clone()); } - return std::make_unique(std::move(providers), miniscript::MakeNodeRef(*m_node)); + return std::make_unique(std::move(providers), m_node->Clone()); } }; @@ -2154,7 +2154,7 @@ std::vector> ParseScript(uint32_t& key_exp_index for (auto& pub : parser.m_keys) { pubs.emplace_back(std::move(pub.at(i))); } - ret.emplace_back(std::make_unique(std::move(pubs), node)); + ret.emplace_back(std::make_unique(std::move(pubs), node->Clone())); } return ret; } diff --git a/src/script/miniscript.h b/src/script/miniscript.h index 58f24434f06..ac0d0469422 100644 --- a/src/script/miniscript.h +++ b/src/script/miniscript.h @@ -523,6 +523,35 @@ struct Node { } } + NodeRef Clone() const + { + // Use TreeEval() to avoid a stack-overflow due to recursion + auto upfn = [](const Node& node, Span> children) { + NodeRef ret; + // As all members of Node are const, except for subs, we need to construct the cloned node with all of these members. + // However, there is no constructor that takes all three of data, keys, and subs. + // But, they are mutually exclusive, so we can use the appropriate constructor depending on what is available. + if (!node.keys.empty()) { + Assert(node.data.empty() && node.subs.empty()); + ret = MakeNodeRef(internal::NoDupCheck{}, node.m_script_ctx, node.fragment, node.keys, node.k); + } else if (!node.data.empty()) { + Assert(node.keys.empty() && node.subs.empty()); + ret = MakeNodeRef(internal::NoDupCheck{}, node.m_script_ctx, node.fragment, node.data, node.k); + } else if (!node.subs.empty()) { + Assert(node.data.empty() && node.keys.empty()); + std::vector> new_subs; + for (auto child = children.begin(); child != children.end(); ++child) { + new_subs.emplace_back(std::move(*child)); + } + ret = MakeNodeRef(internal::NoDupCheck{}, node.m_script_ctx, node.fragment, std::move(new_subs), node.k); + } else { + ret = MakeNodeRef(internal::NoDupCheck{}, node.m_script_ctx, node.fragment, node.k); + } + return ret; + }; + return TreeEval>(upfn); + } + private: //! Cached ops counts. const internal::Ops ops;