| 796 | public: |
| 797 | template<typename Ctx> |
| 798 | CScript ToScript(const Ctx& ctx) const |
| 799 | { |
| 800 | // To construct the CScript for a Miniscript object, we use the TreeEval algorithm. |
| 801 | // The State is a boolean: whether or not the node's script expansion is followed |
| 802 | // by an OP_VERIFY (which may need to be combined with the last script opcode). |
| 803 | auto downfn = [](bool verify, const Node& node, size_t index) { |
| 804 | // For WRAP_V, the subexpression is certainly followed by OP_VERIFY. |
| 805 | if (node.fragment == Fragment::WRAP_V) return true; |
| 806 | // The subexpression of WRAP_S, and the last subexpression of AND_V |
| 807 | // inherit the followed-by-OP_VERIFY property from the parent. |
| 808 | if (node.fragment == Fragment::WRAP_S || |
| 809 | (node.fragment == Fragment::AND_V && index == 1)) return verify; |
| 810 | return false; |
| 811 | }; |
| 812 | // The upward function computes for a node, given its followed-by-OP_VERIFY status |
| 813 | // and the CScripts of its child nodes, the CScript of the node. |
| 814 | const bool is_tapscript{IsTapscript(m_script_ctx)}; |
| 815 | auto upfn = [&ctx, is_tapscript](bool verify, const Node& node, std::span<CScript> subs) -> CScript { |
| 816 | switch (node.fragment) { |
| 817 | case Fragment::PK_K: return BuildScript(ctx.ToPKBytes(node.keys[0])); |
| 818 | case Fragment::PK_H: return BuildScript(OP_DUP, OP_HASH160, ctx.ToPKHBytes(node.keys[0]), OP_EQUALVERIFY); |
| 819 | case Fragment::OLDER: return BuildScript(node.k, OP_CHECKSEQUENCEVERIFY); |
| 820 | case Fragment::AFTER: return BuildScript(node.k, OP_CHECKLOCKTIMEVERIFY); |
| 821 | case Fragment::SHA256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_SHA256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL); |
| 822 | case Fragment::RIPEMD160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_RIPEMD160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL); |
| 823 | case Fragment::HASH256: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH256, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL); |
| 824 | case Fragment::HASH160: return BuildScript(OP_SIZE, 32, OP_EQUALVERIFY, OP_HASH160, node.data, verify ? OP_EQUALVERIFY : OP_EQUAL); |
| 825 | case Fragment::WRAP_A: return BuildScript(OP_TOALTSTACK, subs[0], OP_FROMALTSTACK); |
| 826 | case Fragment::WRAP_S: return BuildScript(OP_SWAP, subs[0]); |
| 827 | case Fragment::WRAP_C: return BuildScript(std::move(subs[0]), verify ? OP_CHECKSIGVERIFY : OP_CHECKSIG); |
| 828 | case Fragment::WRAP_D: return BuildScript(OP_DUP, OP_IF, subs[0], OP_ENDIF); |
| 829 | case Fragment::WRAP_V: { |
| 830 | if (node.subs[0].GetType() << "x"_mst) { |
| 831 | return BuildScript(std::move(subs[0]), OP_VERIFY); |
| 832 | } else { |
| 833 | return std::move(subs[0]); |
| 834 | } |
| 835 | } |
| 836 | case Fragment::WRAP_J: return BuildScript(OP_SIZE, OP_0NOTEQUAL, OP_IF, subs[0], OP_ENDIF); |
| 837 | case Fragment::WRAP_N: return BuildScript(std::move(subs[0]), OP_0NOTEQUAL); |
| 838 | case Fragment::JUST_1: return BuildScript(OP_1); |
| 839 | case Fragment::JUST_0: return BuildScript(OP_0); |
| 840 | case Fragment::AND_V: return BuildScript(std::move(subs[0]), subs[1]); |
| 841 | case Fragment::AND_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLAND); |
| 842 | case Fragment::OR_B: return BuildScript(std::move(subs[0]), subs[1], OP_BOOLOR); |
| 843 | case Fragment::OR_D: return BuildScript(std::move(subs[0]), OP_IFDUP, OP_NOTIF, subs[1], OP_ENDIF); |
| 844 | case Fragment::OR_C: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[1], OP_ENDIF); |
| 845 | case Fragment::OR_I: return BuildScript(OP_IF, subs[0], OP_ELSE, subs[1], OP_ENDIF); |
| 846 | case Fragment::ANDOR: return BuildScript(std::move(subs[0]), OP_NOTIF, subs[2], OP_ELSE, subs[1], OP_ENDIF); |
| 847 | case Fragment::MULTI: { |
| 848 | CHECK_NONFATAL(!is_tapscript); |
| 849 | CScript script = BuildScript(node.k); |
| 850 | for (const auto& key : node.keys) { |
| 851 | script = BuildScript(std::move(script), ctx.ToPKBytes(key)); |
| 852 | } |
| 853 | return BuildScript(std::move(script), node.keys.size(), verify ? OP_CHECKMULTISIGVERIFY : OP_CHECKMULTISIG); |
| 854 | } |
| 855 | case Fragment::MULTI_A: { |