5#ifndef BITCOIN_SCRIPT_MINISCRIPT_H
6#define BITCOIN_SCRIPT_MINISCRIPT_H
153inline consteval Type operator"" _mst(
const char* c,
size_t l) {
156 for (
const char *p = c; p < c + l; p++) {
168 *p ==
'f' ? 1 << 10 :
169 *p ==
's' ? 1 << 11 :
170 *p ==
'm' ? 1 << 12 :
171 *p ==
'x' ? 1 << 13 :
172 *p ==
'g' ? 1 << 14 :
173 *p ==
'h' ? 1 << 15 :
174 *p ==
'i' ? 1 << 16 :
175 *p ==
'j' ? 1 << 17 :
176 *p ==
'k' ? 1 << 18 :
177 (
throw std::logic_error(
"Unknown character in _mst literal"), 0)
184using Opcode = std::pair<opcodetype, std::vector<unsigned char>>;
186template<
typename Key>
struct Node;
187template<
typename Key>
using NodeRef = std::shared_ptr<const Node<Key>>;
190template<
typename Key,
typename... Args>
306 std::vector<std::vector<unsigned char>>
stack;
340 template<
typename A,
typename B>
359 if (!a.
valid)
return b;
360 if (!b.
valid)
return a;
429 constexpr SatInfo(int32_t in_netdiff, int32_t in_exec) noexcept :
436 if (!a.valid)
return b;
437 if (!b.valid)
return a;
439 return {std::max(a.netdiff, b.netdiff), std::max(a.exec, b.exec)};
446 if (!a.valid || !b.valid)
return {};
450 return {a.netdiff + b.netdiff, std::max(b.exec, b.netdiff + a.exec)};
462 static constexpr SatInfo If() noexcept {
return {1, 1}; }
468 static constexpr SatInfo OP_IFDUP(
bool nonzero)
noexcept {
return {nonzero ? -1 : 0, 0}; }
498template<
typename Key>
503 const uint32_t
k = 0;
507 const std::vector<unsigned char>
data;
509 mutable std::vector<NodeRef<Key>>
subs;
516 while (!
subs.empty()) {
519 while (!
node->subs.empty()) {
520 subs.push_back(std::move(
node->subs.back()));
521 node->subs.pop_back();
548 for (
const auto& sub :
subs) {
549 subsize += sub->ScriptSize();
551 static constexpr auto NONE_MST{
""_mst};
552 Type sub0type =
subs.size() > 0 ?
subs[0]->GetType() : NONE_MST;
579 template<
typename Result,
typename State,
typename DownFn,
typename UpFn>
580 std::optional<Result>
TreeEvalMaybe(State root_state, DownFn downfn, UpFn upfn)
const
589 StackElem(
const Node& node_,
size_t exp_, State&& state_) :
590 node(node_), expanded(exp_), state(std::move(state_)) {}
593 std::vector<StackElem> stack;
596 std::vector<Result> results;
597 stack.emplace_back(*
this, 0, std::move(root_state));
615 while (stack.size()) {
616 const Node&
node = stack.back().node;
617 if (stack.back().expanded <
node.subs.size()) {
621 size_t child_index = stack.back().expanded++;
622 State child_state = downfn(stack.back().state,
node, child_index);
623 stack.emplace_back(*
node.subs[child_index], 0, std::move(child_state));
628 std::optional<Result> result{upfn(std::move(stack.back().state),
node,
631 if (!result)
return {};
633 results.erase(results.end() -
node.subs.size(), results.end());
634 results.push_back(std::move(*result));
638 assert(results.size() == 1);
639 return std::move(results[0]);
644 template<
typename Result,
typename UpFn>
647 struct DummyState {};
649 [](DummyState,
const Node&, size_t) {
return DummyState{}; },
657 template<
typename Result,
typename State,
typename DownFn,
typename UpFn>
658 Result
TreeEval(State root_state, DownFn&& downfn, UpFn upfn)
const
663 std::forward<DownFn>(downfn),
665 Result res{upfn(std::move(state),
node,
subs)};
666 return std::optional<Result>(std::move(res));
673 template<
typename Result,
typename UpFn>
676 struct DummyState {};
678 [](DummyState,
const Node&, size_t) {
return DummyState{}; },
681 return std::optional<Result>(std::move(res));
689 std::vector<std::pair<const Node<Key>&,
const Node<Key>&>> queue;
690 queue.emplace_back(node1, node2);
691 while (!queue.empty()) {
692 const auto& [a, b] = queue.back();
694 if (std::tie(a.fragment, a.k, a.keys, a.data) < std::tie(b.fragment, b.k, b.keys, b.data))
return -1;
695 if (std::tie(b.fragment, b.k, b.keys, b.data) < std::tie(a.fragment, a.k, a.keys, a.data))
return 1;
696 if (a.subs.size() < b.subs.size())
return -1;
697 if (b.subs.size() < a.subs.size())
return 1;
698 size_t n = a.subs.size();
699 for (
size_t i = 0; i < n; ++i) {
700 queue.emplace_back(*a.subs[n - 1 - i], *b.subs[n - 1 - i]);
708 using namespace internal;
711 std::vector<Type> sub_types;
713 for (
const auto& sub :
subs) sub_types.push_back(sub->GetType());
716 static constexpr auto NONE_MST{
""_mst};
717 Type x =
subs.size() > 0 ?
subs[0]->GetType() : NONE_MST;
718 Type y =
subs.size() > 1 ?
subs[1]->GetType() : NONE_MST;
719 Type z =
subs.size() > 2 ?
subs[2]->GetType() : NONE_MST;
725 template<
typename Ctx>
744 switch (
node.fragment) {
758 if (
node.subs[0]->GetType() <<
"x"_mst) {
761 return std::move(
subs[0]);
778 for (
const auto& key :
node.keys) {
786 for (
auto it =
node.keys.begin() + 1; it !=
node.keys.end(); ++it) {
793 for (
size_t i = 1; i <
subs.size(); ++i) {
804 template<
typename CTx>
805 std::optional<std::string>
ToString(
const CTx& ctx)
const {
809 auto downfn = [](bool,
const Node&
node, size_t) {
822 std::string
ret = wrapped ?
":" :
"";
824 switch (
node.fragment) {
830 auto key_str = ctx.ToString(
node.subs[0]->keys[0]);
831 if (!key_str)
return {};
832 return std::move(
ret) +
"pk(" + std::move(*key_str) +
")";
836 auto key_str = ctx.ToString(
node.subs[0]->keys[0]);
837 if (!key_str)
return {};
838 return std::move(
ret) +
"pkh(" + std::move(*key_str) +
")";
840 return "c" + std::move(
subs[0]);
855 switch (
node.fragment) {
857 auto key_str = ctx.ToString(
node.keys[0]);
858 if (!key_str)
return {};
859 return std::move(
ret) +
"pk_k(" + std::move(*key_str) +
")";
862 auto key_str = ctx.ToString(
node.keys[0]);
863 if (!key_str)
return {};
864 return std::move(
ret) +
"pk_h(" + std::move(*key_str) +
")";
883 return std::move(
ret) +
"andor(" + std::move(
subs[0]) +
"," + std::move(
subs[1]) +
"," + std::move(
subs[2]) +
")";
887 for (
const auto& key :
node.keys) {
888 auto key_str = ctx.ToString(key);
889 if (!key_str)
return {};
890 str +=
"," + std::move(*key_str);
892 return std::move(str) +
")";
897 for (
const auto& key :
node.keys) {
898 auto key_str = ctx.ToString(key);
899 if (!key_str)
return {};
900 str +=
"," + std::move(*key_str);
902 return std::move(str) +
")";
906 for (
auto& sub :
subs) {
907 str +=
"," + std::move(sub);
909 return std::move(str) +
")";
934 const auto count{1 +
subs[0]->ops.count +
subs[1]->ops.count};
935 const auto sat{
subs[0]->ops.sat +
subs[1]->ops.sat};
936 const auto dsat{
subs[0]->ops.dsat +
subs[1]->ops.dsat};
937 return {
count, sat, dsat};
940 const auto count{1 +
subs[0]->ops.count +
subs[1]->ops.count};
942 const auto dsat{
subs[0]->ops.dsat +
subs[1]->ops.dsat};
943 return {
count, sat, dsat};
946 const auto count{3 +
subs[0]->ops.count +
subs[1]->ops.count};
947 const auto sat{
subs[0]->ops.sat | (
subs[1]->ops.sat +
subs[0]->ops.dsat)};
948 const auto dsat{
subs[0]->ops.dsat +
subs[1]->ops.dsat};
949 return {
count, sat, dsat};
952 const auto count{2 +
subs[0]->ops.count +
subs[1]->ops.count};
953 const auto sat{
subs[0]->ops.sat | (
subs[1]->ops.sat +
subs[0]->ops.dsat)};
954 return {
count, sat, {}};
957 const auto count{3 +
subs[0]->ops.count +
subs[1]->ops.count};
958 const auto sat{
subs[0]->ops.sat |
subs[1]->ops.sat};
959 const auto dsat{
subs[0]->ops.dsat |
subs[1]->ops.dsat};
960 return {
count, sat, dsat};
963 const auto count{3 +
subs[0]->ops.count +
subs[1]->ops.count +
subs[2]->ops.count};
965 const auto dsat{
subs[0]->ops.dsat +
subs[2]->ops.dsat};
966 return {
count, sat, dsat};
980 for (
const auto& sub :
subs) {
981 count += sub->ops.count + 1;
982 auto next_sats =
Vector(sats[0] + sub->ops.dsat);
983 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub->ops.dsat) | (sats[j - 1] + sub->ops.sat));
984 next_sats.push_back(sats[sats.size() - 1] + sub->ops.sat);
985 sats = std::move(next_sats);
988 return {
count, sats[
k], sats[0]};
995 using namespace internal;
1002 case Fragment::PK_H:
return {SatInfo::OP_DUP() + SatInfo::Hash() + SatInfo::Push() + SatInfo::OP_EQUALVERIFY()};
1007 SatInfo::OP_SIZE() + SatInfo::Push() + SatInfo::OP_EQUALVERIFY() + SatInfo::Hash() + SatInfo::Push() + SatInfo::OP_EQUAL(),
1011 const auto& x{
subs[0]->ss};
1012 const auto& y{
subs[1]->ss};
1013 const auto& z{
subs[2]->ss};
1015 (x.sat + SatInfo::If() + y.sat) | (x.dsat + SatInfo::If() + z.sat),
1016 x.dsat + SatInfo::If() + z.dsat
1020 const auto& x{
subs[0]->ss};
1021 const auto& y{
subs[1]->ss};
1022 return {x.sat + y.sat, {}};
1025 const auto& x{
subs[0]->ss};
1026 const auto& y{
subs[1]->ss};
1027 return {x.sat + y.sat + SatInfo::BinaryOp(), x.dsat + y.dsat + SatInfo::BinaryOp()};
1030 const auto& x{
subs[0]->ss};
1031 const auto& y{
subs[1]->ss};
1033 ((x.sat + y.dsat) | (x.dsat + y.sat)) + SatInfo::BinaryOp(),
1034 x.dsat + y.dsat + SatInfo::BinaryOp()
1038 const auto& x{
subs[0]->ss};
1039 const auto& y{
subs[1]->ss};
1040 return {(x.sat + SatInfo::If()) | (x.dsat + SatInfo::If() + y.sat), {}};
1043 const auto& x{
subs[0]->ss};
1044 const auto& y{
subs[1]->ss};
1046 (x.sat + SatInfo::OP_IFDUP(
true) + SatInfo::If()) | (x.dsat + SatInfo::OP_IFDUP(
false) + SatInfo::If() + y.sat),
1047 x.dsat + SatInfo::OP_IFDUP(
false) + SatInfo::If() + y.dsat
1051 const auto& x{
subs[0]->ss};
1052 const auto& y{
subs[1]->ss};
1053 return {SatInfo::If() + (x.sat | y.sat), SatInfo::If() + (x.dsat | y.dsat)};
1068 subs[0]->ss.sat + SatInfo::OP_CHECKSIG(),
1069 subs[0]->ss.dsat + SatInfo::OP_CHECKSIG()
1072 SatInfo::OP_DUP() + SatInfo::If() +
subs[0]->ss.sat,
1073 SatInfo::OP_DUP() + SatInfo::If()
1077 SatInfo::OP_SIZE() + SatInfo::OP_0NOTEQUAL() + SatInfo::If() +
subs[0]->ss.sat,
1078 SatInfo::OP_SIZE() + SatInfo::OP_0NOTEQUAL() + SatInfo::If()
1082 auto sats =
Vector(SatInfo::Empty());
1083 for (
size_t i = 0; i <
subs.size(); ++i) {
1086 auto add = i ? SatInfo::BinaryOp() : SatInfo::Empty();
1090 for (
size_t j = 1; j < sats.size(); ++j) {
1091 next_sats.push_back(((sats[j] +
subs[i]->
ss.
dsat) | (sats[j - 1] +
subs[i]->ss.sat)) + add);
1094 next_sats.push_back(sats[sats.size() - 1] +
subs[i]->ss.sat + add);
1096 sats = std::move(next_sats);
1101 sats[
k] + SatInfo::Push() + SatInfo::OP_EQUAL(),
1102 sats[0] + SatInfo::Push() + SatInfo::OP_EQUAL()
1118 case Fragment::PK_H:
return {sig_size + pubkey_size, 1 + pubkey_size};
1125 const auto dsat{
subs[0]->ws.dsat +
subs[2]->ws.dsat};
1132 const auto dsat{
subs[0]->ws.dsat +
subs[1]->ws.dsat};
1149 for (
const auto& sub :
subs) {
1150 auto next_sats =
Vector(sats[0] + sub->ws.dsat);
1151 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub->ws.dsat) | (sats[j - 1] + sub->ws.sat));
1152 next_sats.push_back(sats[sats.size() - 1] + sub->ws.sat);
1153 sats = std::move(next_sats);
1156 return {sats[
k], sats[0]};
1162 template<
typename Ctx>
1164 using namespace internal;
1169 switch (
node.fragment) {
1171 std::vector<unsigned char> sig;
1173 return {ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
1176 std::vector<unsigned char> key = ctx.ToPKBytes(
node.keys[0]), sig;
1178 return {ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
1184 for (
size_t i = 0; i <
node.keys.size(); ++i) {
1187 std::vector<unsigned char> sig;
1190 auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1194 std::vector<InputStack> next_sats;
1195 next_sats.push_back(sats[0] + ZERO);
1196 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + ZERO) | (std::move(sats[j - 1]) + sat));
1197 next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1199 sats = std::move(next_sats);
1203 auto& nsat{sats[0]};
1206 return {std::move(nsat), std::move(sats[
node.k])};
1212 std::vector<InputStack> sats =
Vector(ZERO);
1213 for (
size_t i = 0; i <
node.keys.size(); ++i) {
1214 std::vector<unsigned char> sig;
1217 auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1221 std::vector<InputStack> next_sats;
1222 next_sats.push_back(sats[0]);
1223 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
1224 next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1226 sats = std::move(next_sats);
1229 InputStack nsat = ZERO;
1230 for (
size_t i = 0; i <
node.k; ++i) nsat = std::move(nsat) + ZERO;
1232 return {std::move(nsat), std::move(sats[
node.k])};
1239 for (
size_t i = 0; i < subres.size(); ++i) {
1241 auto& res = subres[subres.size() - i - 1];
1245 std::vector<InputStack> next_sats;
1246 next_sats.push_back(sats[0] + res.nsat);
1247 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + res.nsat) | (std::move(sats[j - 1]) + res.sat));
1248 next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
1250 sats = std::move(next_sats);
1255 for (
size_t i = 0; i < sats.size(); ++i) {
1262 if (i != 0 && i !=
node.k) sats[i].SetMalleable().SetNonCanon();
1264 if (i !=
node.k) nsat = std::move(nsat) | std::move(sats[i]);
1267 return {std::move(nsat), std::move(sats[
node.k])};
1276 std::vector<unsigned char> preimage;
1278 return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1281 std::vector<unsigned char> preimage;
1283 return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1286 std::vector<unsigned char> preimage;
1288 return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1291 std::vector<unsigned char> preimage;
1293 return {ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1296 auto& x = subres[0], &y = subres[1];
1303 return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
1306 auto& x = subres[0], &y = subres[1];
1312 return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
1315 auto& x = subres[0], &z = subres[1];
1317 return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
1320 auto& x = subres[0], &z = subres[1];
1321 return {
INVALID, std::move(x.sat) | (z.sat + x.nsat)};
1324 auto& x = subres[0], &z = subres[1];
1325 return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
1328 auto& x = subres[0], &z = subres[1];
1329 return {(x.nsat + ONE) | (z.nsat + ZERO), (x.sat + ONE) | (z.sat + ZERO)};
1332 auto& x = subres[0], &y = subres[1], &z = subres[2];
1333 return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
1339 return std::move(subres[0]);
1341 auto &x = subres[0];
1342 return {ZERO, x.sat + ONE};
1345 auto &x = subres[0];
1351 return {InputStack(ZERO).SetMalleable(x.nsat.available !=
Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
1354 auto &x = subres[0];
1355 return {
INVALID, std::move(x.sat)};
1365 auto ret = helper(
node, subres);
1388 if (
node.GetType() <<
"d"_mst && !
ret.nsat.malleable)
assert(!
ret.nsat.non_canon);
1396 if (
node.GetType() <<
"me"_mst)
assert(!
ret.nsat.malleable);
1422 Comp(
const Ctx& ctx) : ctx_ptr(&ctx) {}
1423 bool operator()(
const Key& a,
const Key& b)
const {
return ctx_ptr->KeyCompare(a, b); }
1429 using keyset = std::set<Key, Comp>;
1430 using state = std::optional<keyset>;
1434 if (
node.has_duplicate_keys.has_value() && *
node.has_duplicate_keys)
return {};
1437 for (
auto& sub :
subs) {
1438 if (!sub.has_value()) {
1439 node.has_duplicate_keys =
true;
1446 size_t keys_count =
node.keys.size();
1447 keyset key_set{
node.keys.begin(),
node.keys.end(), Comp(ctx)};
1448 if (key_set.size() != keys_count) {
1450 node.has_duplicate_keys =
true;
1455 for (
auto& sub :
subs) {
1456 keys_count += sub->size();
1459 if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1460 key_set.merge(*sub);
1461 if (key_set.size() != keys_count) {
1462 node.has_duplicate_keys =
true;
1467 node.has_duplicate_keys =
false;
1495 return !((
GetType() &
"BKW"_mst) ==
""_mst);
1541 for (
auto& sub:
subs)
if (sub)
return sub;
1542 if (!
node.IsSaneSubexpression())
return &
node;
1549 template<
typename F>
1554 switch (
node.fragment) {
1569 return bool{fn(
node)};
1581 return static_cast<uint32_t
>(std::count(
subs.begin(),
subs.end(),
true)) >=
node.k;
1591 if (
GetType() ==
""_mst)
return false;
1623 template<
typename Ctx>
1624 Availability Satisfy(
const Ctx& ctx, std::vector<std::vector<unsigned char>>& stack,
bool nonmalleable =
true)
const {
1627 stack = std::move(
ret.sat.stack);
1628 return ret.sat.available;
1649 template <
typename Ctx>
Node(
const Ctx& ctx,
Fragment nt, std::vector<
NodeRef<Key>> sub, std::vector<unsigned char> arg, uint32_t val = 0)
1651 template <
typename Ctx>
Node(
const Ctx& ctx,
Fragment nt, std::vector<unsigned char> arg, uint32_t val = 0)
1655 template <
typename Ctx>
Node(
const Ctx& ctx,
Fragment nt, std::vector<Key> key, uint32_t val = 0)
1659 template <
typename Ctx>
Node(
const Ctx& ctx,
Fragment nt, uint32_t val = 0)
1722template<
typename Key,
typename Ctx>
1726 if (key_size < 1)
return {};
1727 auto key = ctx.FromString(in.
begin(), in.
begin() + key_size);
1728 if (!key)
return {};
1729 return {{std::move(*key), key_size}};
1733template<
typename Ctx>
1738 if (hash_size < 1)
return {};
1739 std::string val = std::string(in.
begin(), in.
begin() + hash_size);
1740 if (!
IsHex(val))
return {};
1742 if (hash.size() != expected_size)
return {};
1743 return {{std::move(hash), hash_size}};
1747template<
typename Key>
1751 constructed.pop_back();
1764template<
typename Key,
typename Ctx>
1779 size_t script_size{1};
1783 std::vector<std::tuple<ParseContext, int64_t, int64_t>> to_parse;
1784 std::vector<NodeRef<Key>> constructed;
1789 const auto parse_multi_exp = [&](
Span<const char>& in,
const bool is_multi_a) ->
bool {
1792 if (ctx.MsContext() != required_ctx)
return false;
1795 if (next_comma < 1)
return false;
1797 if (!k_to_integral.has_value())
return false;
1798 const int64_t
k{k_to_integral.value()};
1799 in = in.
subspan(next_comma + 1);
1801 std::vector<Key> keys;
1802 while (next_comma != -1) {
1804 int key_length = (next_comma == -1) ?
FindNextChar(in,
')') : next_comma;
1805 if (key_length < 1)
return false;
1806 auto key = ctx.FromString(in.
begin(), in.
begin() + key_length);
1807 if (!key)
return false;
1808 keys.push_back(std::move(*key));
1809 in = in.
subspan(key_length + 1);
1811 if (keys.size() < 1 || keys.size() > max_keys)
return false;
1818 script_size += 2 + (keys.size() > 16) + (
k > 16) + 34 * keys.size();
1824 while (!to_parse.empty()) {
1825 if (script_size > max_size)
return {};
1828 auto [cur_context, n,
k] = to_parse.back();
1829 to_parse.pop_back();
1831 switch (cur_context) {
1833 std::optional<size_t> colon_index{};
1834 for (
size_t i = 1; i < in.
size(); ++i) {
1839 if (in[i] <
'a' || in[i] >
'z')
break;
1842 bool last_was_v{
false};
1843 for (
size_t j = 0; colon_index && j < *colon_index; ++j) {
1844 if (script_size > max_size)
return {};
1848 }
else if (in[j] ==
's') {
1851 }
else if (in[j] ==
'c') {
1854 }
else if (in[j] ==
'd') {
1857 }
else if (in[j] ==
'j') {
1860 }
else if (in[j] ==
'n') {
1863 }
else if (in[j] ==
'v') {
1866 if (last_was_v)
return {};
1868 }
else if (in[j] ==
'u') {
1871 }
else if (in[j] ==
't') {
1874 }
else if (in[j] ==
'l') {
1882 last_was_v = (in[j] ==
'v');
1885 if (colon_index) in = in.
subspan(*colon_index + 1);
1889 if (Const(
"0", in)) {
1891 }
else if (Const(
"1", in)) {
1893 }
else if (Const(
"pk(", in)) {
1895 if (!res)
return {};
1896 auto& [key, key_size] = *res;
1898 in = in.
subspan(key_size + 1);
1899 script_size +=
IsTapscript(ctx.MsContext()) ? 33 : 34;
1900 }
else if (Const(
"pkh(", in)) {
1902 if (!res)
return {};
1903 auto& [key, key_size] = *res;
1905 in = in.
subspan(key_size + 1);
1907 }
else if (Const(
"pk_k(", in)) {
1909 if (!res)
return {};
1910 auto& [key, key_size] = *res;
1912 in = in.
subspan(key_size + 1);
1913 script_size +=
IsTapscript(ctx.MsContext()) ? 32 : 33;
1914 }
else if (Const(
"pk_h(", in)) {
1916 if (!res)
return {};
1917 auto& [key, key_size] = *res;
1919 in = in.
subspan(key_size + 1);
1921 }
else if (Const(
"sha256(", in)) {
1923 if (!res)
return {};
1924 auto& [hash, hash_size] = *res;
1926 in = in.
subspan(hash_size + 1);
1928 }
else if (Const(
"ripemd160(", in)) {
1930 if (!res)
return {};
1931 auto& [hash, hash_size] = *res;
1933 in = in.
subspan(hash_size + 1);
1935 }
else if (Const(
"hash256(", in)) {
1937 if (!res)
return {};
1938 auto& [hash, hash_size] = *res;
1940 in = in.
subspan(hash_size + 1);
1942 }
else if (Const(
"hash160(", in)) {
1944 if (!res)
return {};
1945 auto& [hash, hash_size] = *res;
1947 in = in.
subspan(hash_size + 1);
1949 }
else if (Const(
"after(", in)) {
1951 if (arg_size < 1)
return {};
1953 if (!num.has_value() || *num < 1 || *num >= 0x80000000L)
return {};
1955 in = in.
subspan(arg_size + 1);
1956 script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
1957 }
else if (Const(
"older(", in)) {
1959 if (arg_size < 1)
return {};
1961 if (!num.has_value() || *num < 1 || *num >= 0x80000000L)
return {};
1963 in = in.
subspan(arg_size + 1);
1964 script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
1965 }
else if (Const(
"multi(", in)) {
1966 if (!parse_multi_exp(in,
false))
return {};
1967 }
else if (Const(
"multi_a(", in)) {
1968 if (!parse_multi_exp(in,
true))
return {};
1969 }
else if (Const(
"thresh(", in)) {
1971 if (next_comma < 1)
return {};
1973 if (!
k.has_value() || *
k < 1)
return {};
1974 in = in.
subspan(next_comma + 1);
1978 script_size += 2 + (*
k > 16) + (*
k > 0x7f) + (*
k > 0x7fff) + (*
k > 0x7fffff);
1979 }
else if (Const(
"andor(", in)) {
1989 if (Const(
"and_n(", in)) {
1992 }
else if (Const(
"and_b(", in)) {
1995 }
else if (Const(
"and_v(", in)) {
1998 }
else if (Const(
"or_b(", in)) {
2001 }
else if (Const(
"or_c(", in)) {
2004 }
else if (Const(
"or_d(", in)) {
2007 }
else if (Const(
"or_i(", in)) {
2045 script_size += (constructed.back()->GetType() <<
"x"_mst);
2062 auto mid = std::move(constructed.back());
2063 constructed.pop_back();
2088 auto right = std::move(constructed.back());
2089 constructed.pop_back();
2090 auto mid = std::move(constructed.back());
2091 constructed.pop_back();
2096 if (in.
size() < 1)
return {};
2102 }
else if (in[0] ==
')') {
2103 if (
k > n)
return {};
2106 std::vector<NodeRef<Key>> subs;
2107 for (
int i = 0; i < n; ++i) {
2108 subs.push_back(std::move(constructed.back()));
2109 constructed.pop_back();
2111 std::reverse(subs.begin(), subs.end());
2119 if (in.
size() < 1 || in[0] !=
',')
return {};
2124 if (in.
size() < 1 || in[0] !=
')')
return {};
2132 assert(constructed.size() == 1);
2133 assert(constructed[0]->ScriptSize() == script_size);
2134 if (in.
size() > 0)
return {};
2136 tl_node->DuplicateKeyCheck(ctx);
2222template<
typename Key,
typename Ctx,
typename I>
2226 std::vector<std::tuple<DecodeContext, int64_t, int64_t>> to_parse;
2227 std::vector<NodeRef<Key>> constructed;
2233 while (!to_parse.empty()) {
2235 if (!constructed.empty() && !constructed.back()->IsValid())
return {};
2238 auto [cur_context, n,
k] = to_parse.back();
2239 to_parse.pop_back();
2241 switch(cur_context) {
2243 if (in >= last)
return {};
2246 if (in[0].first ==
OP_1) {
2251 if (in[0].first ==
OP_0) {
2257 if (in[0].second.size() == 33 || in[0].second.size() == 32) {
2258 auto key = ctx.FromPKBytes(in[0].second.begin(), in[0].second.end());
2259 if (!key)
return {};
2265 auto key = ctx.FromPKHBytes(in[2].second.begin(), in[2].second.end());
2266 if (!key)
return {};
2272 std::optional<int64_t> num;
2275 if (*num < 1 || *num > 0x7FFFFFFFL)
return {};
2281 if (num < 1 || num > 0x7FFFFFFFL)
return {};
2287 if (in[2].first ==
OP_SHA256 && in[1].second.size() == 32) {
2291 }
else if (in[2].first ==
OP_RIPEMD160 && in[1].second.size() == 20) {
2295 }
else if (in[2].first ==
OP_HASH256 && in[1].second.size() == 32) {
2299 }
else if (in[2].first ==
OP_HASH160 && in[1].second.size() == 20) {
2308 std::vector<Key> keys;
2310 if (!n || last - in < 3 + *n)
return {};
2311 if (*n < 1 || *n > 20)
return {};
2312 for (
int i = 0; i < *n; ++i) {
2313 if (in[2 + i].second.size() != 33)
return {};
2314 auto key = ctx.FromPKBytes(in[2 + i].second.begin(), in[2 + i].second.end());
2315 if (!key)
return {};
2316 keys.push_back(std::move(*key));
2321 std::reverse(keys.begin(), keys.end());
2326 if (last - in >= 4 && in[0].first ==
OP_NUMEQUAL) {
2332 if (last - in < 2 + *
k * 2)
return {};
2333 std::vector<Key> keys;
2336 for (
int pos = 2;; pos += 2) {
2337 if (last - in < pos + 2)
return {};
2340 if (in[pos + 1].second.size() != 32)
return {};
2341 auto key = ctx.FromPKBytes(in[pos + 1].second.begin(), in[pos + 1].second.end());
2342 if (!key)
return {};
2343 keys.push_back(std::move(*key));
2349 if (keys.size() < (
size_t)*
k)
return {};
2350 in += 2 + keys.size() * 2;
2351 std::reverse(keys.begin(), keys.end());
2381 if (*num < 1)
return {};
2424 if (in >= last)
return {};
2445 if (in >= last || in[0].first !=
OP_SWAP || constructed.empty())
return {};
2451 if (in >= last || in[0].first !=
OP_TOALTSTACK || constructed.empty())
return {};
2457 if (constructed.empty())
return {};
2462 if (constructed.empty())
return {};
2467 if (constructed.empty())
return {};
2472 if (constructed.empty())
return {};
2477 if (constructed.empty())
return {};
2482 if (constructed.size() < 2)
return {};
2487 if (constructed.size() < 2)
return {};
2492 if (constructed.size() < 2)
return {};
2497 if (constructed.size() < 2)
return {};
2502 if (constructed.size() < 2)
return {};
2507 if (constructed.size() < 3)
return {};
2509 constructed.pop_back();
2511 constructed.pop_back();
2517 if (in >= last)
return {};
2518 if (in[0].first ==
OP_ADD) {
2530 if (
k < 1 || k > n || constructed.size() <
static_cast<size_t>(n))
return {};
2531 std::vector<NodeRef<Key>> subs;
2532 for (
int i = 0; i < n; ++i) {
2534 constructed.pop_back();
2535 subs.push_back(std::move(sub));
2541 if (in >= last)
return {};
2550 else if (in[0].first ==
OP_IF) {
2551 if (last - in >= 2 && in[1].first ==
OP_DUP) {
2562 }
else if (in[0].first ==
OP_NOTIF) {
2572 if (in >= last)
return {};
2584 if (in >= last)
return {};
2585 if (in[0].first ==
OP_IF) {
2588 }
else if (in[0].first ==
OP_NOTIF) {
2600 if (constructed.size() != 1)
return {};
2602 tl_node->DuplicateKeyCheck(ctx);
2605 if (!tl_node->IsValidTopLevel())
return {};
2611template<
typename Ctx>
2616template<
typename Ctx>
2618 using namespace internal;
2620 if (
script.size() > MaxScriptSize(ctx.MsContext()))
return {};
2621 auto decomposed = DecomposeScript(
script);
2622 if (!decomposed)
return {};
2623 auto it = decomposed->begin();
2624 auto ret = DecodeScript<typename Ctx::Key>(it, decomposed->end(), ctx);
2625 if (!
ret)
return {};
2626 if (it != decomposed->end())
return {};
#define CHECK_NONFATAL(condition)
Identity function.
Serialized script, used inside transaction inputs and outputs.
A Span is an object that can refer to a contiguous sequence of objects.
CONSTEXPR_IF_NOT_DEBUG Span< C > last(std::size_t count) const noexcept
constexpr std::size_t size() const noexcept
CONSTEXPR_IF_NOT_DEBUG Span< C > subspan(std::size_t offset) const noexcept
constexpr C * begin() const noexcept
This type encapsulates the miniscript type system properties.
static consteval Type Make(uint32_t flags) noexcept
Construction function used by the ""_mst operator.
constexpr bool operator<<(Type x) const
Check whether the left hand's properties are superset of the right's (= left is a subtype of right).
uint32_t m_flags
Internal bitmap of properties (see ""_mst operator for details).
constexpr Type If(bool x) const
The empty type if x is false, itself otherwise.
constexpr Type operator&(Type x) const
Compute the type with the intersection of properties.
constexpr bool operator<(Type x) const
Comparison operator to enable use in sets/maps (total ordering incompatible with <<).
constexpr Type operator|(Type x) const
Compute the type with the union of properties.
constexpr bool operator==(Type x) const
Equality operator.
constexpr Type(uint32_t flags) noexcept
Internal constructor.
static const int WITNESS_SCALE_FACTOR
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
static constexpr size_t TAPROOT_CONTROL_MAX_SIZE
size_t ComputeScriptLen(Fragment fragment, Type sub0typ, size_t subsize, uint32_t k, size_t n_subs, size_t n_keys, MiniscriptContext ms_ctx)
Helper function for Node::CalcScriptLen.
int FindNextChar(Span< const char > sp, const char m)
std::optional< int64_t > ParseScriptNumber(const Opcode &in)
Determine whether the passed pair (created by DecomposeScript) is pushing a number.
Type SanitizeType(Type e)
A helper sanitizer/checker for the output of CalcType.
std::optional< std::vector< Opcode > > DecomposeScript(const CScript &script)
Decode a script into opcode/push pairs.
NodeRef< Key > DecodeScript(I &in, I last, const Ctx &ctx)
Parse a miniscript from a bitcoin script.
NodeRef< Key > Parse(Span< const char > in, const Ctx &ctx)
Parse a miniscript from its textual descriptor form.
constexpr uint32_t TX_BODY_LEEWAY_WEIGHT
Data other than the witness in a transaction. Overhead + vin count + one vin + vout count + one vout ...
constexpr uint32_t TXIN_BYTES_NO_WITNESS
prevout + nSequence + scriptSig
static const auto ONE
A stack consisting of a single 0x01 element (interpreted as 1 by the script interpreted in numeric co...
static const auto ZERO32
A stack consisting of a single malleable 32-byte 0x0000...0000 element (for dissatisfying hash challe...
std::optional< std::pair< std::vector< unsigned char >, int > > ParseHexStrEnd(Span< const char > in, const size_t expected_size, const Ctx &ctx)
Parse a hex string ending at the end of the fragment's text representation.
constexpr uint32_t MaxScriptSize(MiniscriptContext ms_ctx)
The maximum size of a script depending on the context.
constexpr uint32_t TX_OVERHEAD
version + nLockTime
static const auto ZERO
A stack consisting of a single zero-length element (interpreted as 0 by the script interpreter in num...
std::optional< std::pair< Key, int > > ParseKeyEnd(Span< const char > in, const Ctx &ctx)
Parse a key string ending at the end of the fragment's text representation.
constexpr uint32_t P2WSH_TXOUT_BYTES
nValue + script len + OP_0 + pushdata 32.
@ OR_I
OR_I will construct an or_i node from the last two constructed nodes.
@ VERIFY
VERIFY wraps the top constructed node with v:
@ OR_B
OR_B will construct an or_b node from the last two constructed nodes.
@ CLOSE_BRACKET
CLOSE_BRACKET expects the next element to be ')' and fails if not.
@ AND_N
AND_N will construct an andor(X,Y,0) node from the last two constructed nodes.
@ SWAP
SWAP wraps the top constructed node with s:
@ ANDOR
ANDOR will construct an andor node from the last three constructed nodes.
@ THRESH
THRESH will read a wrapped expression, and then look for a COMMA.
@ COMMA
COMMA expects the next element to be ',' and fails if not.
@ AND_V
AND_V will construct an and_v node from the last two constructed nodes.
@ CHECK
CHECK wraps the top constructed node with c:
@ DUP_IF
DUP_IF wraps the top constructed node with d:
@ OR_C
OR_C will construct an or_c node from the last two constructed nodes.
@ EXPR
A miniscript expression which does not begin with wrappers.
@ ZERO_NOTEQUAL
ZERO_NOTEQUAL wraps the top constructed node with n:
@ NON_ZERO
NON_ZERO wraps the top constructed node with j:
@ WRAP_T
WRAP_T will construct an and_v(X,1) node from the top constructed node.
@ OR_D
OR_D will construct an or_d node from the last two constructed nodes.
@ AND_B
AND_B will construct an and_b node from the last two constructed nodes.
@ ALT
ALT wraps the top constructed node with a:
@ WRAP_U
WRAP_U will construct an or_i(X,0) node from the top constructed node.
@ WRAPPED_EXPR
An expression which may be begin with wrappers followed by a colon.
static const auto INVALID
A stack representing the lack of any (dis)satisfactions.
@ VERIFY
VERIFY wraps the top constructed node with v:
@ SINGLE_BKV_EXPR
A single expression of type B, K, or V.
@ OR_B
OR_B will construct an or_b node from the last two constructed nodes.
@ ENDIF_NOTIF
If, inside an ENDIF context, we find an OP_NOTIF before finding an OP_ELSE, we could either be in an ...
@ BKV_EXPR
Potentially multiple SINGLE_BKV_EXPRs as children of (potentially multiple) and_v expressions.
@ ENDIF_ELSE
If, inside an ENDIF context, we find an OP_ELSE, then we could be in either an or_i or an andor node.
@ MAYBE_AND_V
MAYBE_AND_V will check if the next part of the script could be a valid miniscript sub-expression,...
@ SWAP
SWAP expects the next element to be OP_SWAP (inside a W-type expression that didn't end with FROMALTS...
@ ANDOR
ANDOR will construct an andor node from the last three constructed nodes.
@ W_EXPR
An expression of type W (a: or s: wrappers).
@ AND_V
AND_V will construct an and_v node from the last two constructed nodes.
@ THRESH_E
THRESH_E constructs a thresh node from the appropriate number of constructed children.
@ CHECK
CHECK wraps the top constructed node with c:
@ DUP_IF
DUP_IF wraps the top constructed node with d:
@ OR_C
OR_C will construct an or_c node from the last two constructed nodes.
@ ENDIF
ENDIF signals that we are inside some sort of OP_IF structure, which could be or_d,...
@ ZERO_NOTEQUAL
ZERO_NOTEQUAL wraps the top constructed node with n:
@ NON_ZERO
NON_ZERO wraps the top constructed node with j:
@ OR_D
OR_D will construct an or_d node from the last two constructed nodes.
@ AND_B
AND_B will construct an and_b node from the last two constructed nodes.
@ ALT
ALT expects the next element to be TOALTSTACK (we must have already read a FROMALTSTACK earlier),...
@ THRESH_W
In a thresh expression, all sub-expressions other than the first are W-type, and end in OP_ADD.
constexpr uint32_t MAX_TAPSCRIPT_SAT_SIZE
Maximum possible stack size to spend a Taproot output (excluding the script itself).
static const auto EMPTY
The empty stack.
Type ComputeType(Fragment fragment, Type x, Type y, Type z, const std::vector< Type > &sub_types, uint32_t k, size_t data_size, size_t n_subs, size_t n_keys, MiniscriptContext ms_ctx)
Helper function for Node::CalcType.
void BuildBack(const MiniscriptContext script_ctx, Fragment nt, std::vector< NodeRef< Key > > &constructed, const bool reverse=false)
BuildBack pops the last two elements off constructed and wraps them in the specified Fragment.
static constexpr uint32_t MAX_TAPMINISCRIPT_STACK_ELEM_SIZE
The maximum size of a witness item for a Miniscript under Tapscript context. (A BIP340 signature with...
NodeRef< typename Ctx::Key > FromString(const std::string &str, const Ctx &ctx)
std::pair< opcodetype, std::vector< unsigned char > > Opcode
constexpr bool IsTapscript(MiniscriptContext ms_ctx)
Whether the context Tapscript, ensuring the only other possibility is P2WSH.
std::shared_ptr< const Node< Key > > NodeRef
NodeRef< typename Ctx::Key > FromScript(const CScript &script, const Ctx &ctx)
NodeRef< Key > MakeNodeRef(Args &&... args)
Construct a miniscript node as a shared_ptr.
Fragment
The different node types in miniscript.
@ OR_I
OP_IF [X] OP_ELSE [Y] OP_ENDIF.
@ MULTI_A
[key_0] OP_CHECKSIG ([key_n] OP_CHECKSIGADD)* [k] OP_NUMEQUAL (only within Tapscript ctx)
@ RIPEMD160
OP_SIZE 32 OP_EQUALVERIFY OP_RIPEMD160 [hash] OP_EQUAL.
@ HASH160
OP_SIZE 32 OP_EQUALVERIFY OP_HASH160 [hash] OP_EQUAL.
@ WRAP_A
OP_TOALTSTACK [X] OP_FROMALTSTACK.
@ WRAP_V
[X] OP_VERIFY (or -VERIFY version of last opcode in X)
@ ANDOR
[X] OP_NOTIF [Z] OP_ELSE [Y] OP_ENDIF
@ THRESH
[X1] ([Xn] OP_ADD)* [k] OP_EQUAL
@ OR_C
[X] OP_NOTIF [Y] OP_ENDIF
@ HASH256
OP_SIZE 32 OP_EQUALVERIFY OP_HASH256 [hash] OP_EQUAL.
@ OLDER
[n] OP_CHECKSEQUENCEVERIFY
@ SHA256
OP_SIZE 32 OP_EQUALVERIFY OP_SHA256 [hash] OP_EQUAL.
@ WRAP_J
OP_SIZE OP_0NOTEQUAL OP_IF [X] OP_ENDIF.
@ AFTER
[n] OP_CHECKLOCKTIMEVERIFY
@ OR_D
[X] OP_IFDUP OP_NOTIF [Y] OP_ENDIF
@ WRAP_D
OP_DUP OP_IF [X] OP_ENDIF.
@ AND_B
[X] [Y] OP_BOOLAND
@ PK_H
OP_DUP OP_HASH160 [keyhash] OP_EQUALVERIFY.
@ MULTI
[k] [key_n]* [n] OP_CHECKMULTISIG (only available within P2WSH context)
std::string ToString(const T &t)
Locale-independent version of std::to_string.
static constexpr unsigned int MAX_STANDARD_P2WSH_STACK_ITEMS
The maximum number of witness stack items in a standard P2WSH script.
static constexpr int32_t MAX_STANDARD_TX_WEIGHT
The maximum weight for transactions we're willing to relay/mine.
static constexpr unsigned int MAX_STANDARD_P2WSH_SCRIPT_SIZE
The maximum size in bytes of a standard witnessScript.
static constexpr unsigned int MAX_PUBKEYS_PER_MULTI_A
The limit of keys in OP_CHECKSIGADD-based scripts.
static const int MAX_STACK_SIZE
static const int MAX_OPS_PER_SCRIPT
CScript BuildScript(Ts &&... inputs)
Build a script by concatenating other scripts, or any argument accepted by CScript::operator<<.
static const int MAX_PUBKEYS_PER_MULTISIG
static bool verify(const CScriptNum10 &bignum, const CScriptNum &scriptnum)
constexpr unsigned int GetSizeOfCompactSize(uint64_t nSize)
Compact Size size < 253 – 1 byte size <= USHRT_MAX – 3 bytes (253 + 2 bytes) size <= UINT_MAX – 5 byt...
std::vector< Byte > ParseHex(std::string_view hex_str)
Like TryParseHex, but returns an empty vector on invalid input.
std::optional< T > ToIntegral(std::string_view str)
Convert string to integral type T.
A node in a miniscript expression.
const Type typ
Cached expression type (computed by CalcType and fed through SanitizeType).
uint32_t GetStaticOps() const
Return the number of ops in the script (not counting the dynamic ones that depend on execution).
Result TreeEval(UpFn upfn) const
Like TreeEval, but without downfn or State type.
const Node * FindInsaneSub() const
Find an insane subnode which has no insane children. Nullptr if there is none.
bool IsBKW() const
Whether this node is of type B, K or W.
internal::InputResult ProduceInput(const Ctx &ctx) const
CScript ToScript(const Ctx &ctx) const
bool CheckStackSize() const
Check the maximum stack size for this script against the policy limit.
internal::StackSize CalcStackSize() const
bool IsSaneSubexpression() const
Whether the apparent policy of this node matches its script semantics. Doesn't guarantee it is a safe...
Type GetType() const
Return the expression type.
Node(internal::NoDupCheck, MiniscriptContext script_ctx, Fragment nt, std::vector< NodeRef< Key > > sub, uint32_t val=0)
friend int Compare(const Node< Key > &node1, const Node< Key > &node2)
Compare two miniscript subtrees, using a non-recursive algorithm.
const size_t scriptlen
Cached script length (computed by CalcScriptLen).
std::optional< uint32_t > GetStackSize() const
Return the maximum number of stack elements needed to satisfy this script non-malleably.
std::optional< bool > has_duplicate_keys
Whether a public key appears more than once in this node.
const uint32_t k
The k parameter (time for OLDER/AFTER, threshold for THRESH(_M))
std::optional< uint32_t > GetExecStackSize() const
Return the maximum size of the stack during execution of this script.
bool NeedsSignature() const
Check whether this script always needs a signature.
bool CheckOpsLimit() const
Check the ops limit of this script against the consensus limit.
std::vector< NodeRef< Key > > subs
Subexpressions (for WRAP_*/AND_*/OR_*/ANDOR/THRESH)
Node(internal::NoDupCheck, MiniscriptContext script_ctx, Fragment nt, std::vector< unsigned char > arg, uint32_t val=0)
const Fragment fragment
What node type this node is.
std::optional< uint32_t > GetWitnessSize() const
Return the maximum size in bytes of a witness to satisfy this script non-malleably.
Node(const Ctx &ctx, Fragment nt, std::vector< NodeRef< Key > > sub, uint32_t val=0)
Node(const Ctx &ctx, Fragment nt, uint32_t val=0)
Node(const Ctx &ctx, Fragment nt, std::vector< NodeRef< Key > > sub, std::vector< Key > key, uint32_t val=0)
std::optional< Result > TreeEvalMaybe(UpFn upfn) const
Like TreeEvalMaybe, but without downfn or State type.
internal::WitnessSize CalcWitnessSize() const
Node(internal::NoDupCheck, MiniscriptContext script_ctx, Fragment nt, uint32_t val=0)
Result TreeEval(State root_state, DownFn &&downfn, UpFn upfn) const
Like TreeEvalMaybe, but always produces a result.
internal::Ops CalcOps() const
std::optional< std::string > ToString(const CTx &ctx) const
const MiniscriptContext m_script_ctx
The Script context for this node. Either P2WSH or Tapscript.
size_t CalcScriptLen() const
Compute the length of the script for this miniscript (including children).
std::optional< Result > TreeEvalMaybe(State root_state, DownFn downfn, UpFn upfn) const
bool IsSane() const
Check whether this node is safe as a script on its own.
bool IsValidTopLevel() const
Check whether this node is valid as a script on its own.
bool IsNotSatisfiable() const
Whether no satisfaction exists for this node.
const internal::WitnessSize ws
Cached witness size bounds.
bool IsNonMalleable() const
Check whether this script can always be satisfied in a non-malleable way.
Type CalcType() const
Compute the type for this miniscript.
bool CheckDuplicateKey() const
Check whether there is no duplicate key across this fragment and all its sub-fragments.
Node(const Ctx &ctx, Fragment nt, std::vector< NodeRef< Key > > sub, std::vector< unsigned char > arg, uint32_t val=0)
size_t ScriptSize() const
Return the size of the script for this expression (faster than ToScript().size()).
bool ValidSatisfactions() const
Whether successful non-malleable satisfactions are guaranteed to be valid.
const std::vector< Key > keys
The keys used by this expression (only for PK_K/PK_H/MULTI)
void DuplicateKeyCheck(const Ctx &ctx) const
Update duplicate key information in this Node.
bool operator==(const Node< Key > &arg) const
Equality testing.
Node(internal::NoDupCheck, MiniscriptContext script_ctx, Fragment nt, std::vector< Key > key, uint32_t val=0)
Node(internal::NoDupCheck, MiniscriptContext script_ctx, Fragment nt, std::vector< NodeRef< Key > > sub, std::vector< Key > key, uint32_t val=0)
std::optional< uint32_t > GetOps() const
Return the maximum number of ops needed to satisfy this script non-malleably.
bool CheckTimeLocksMix() const
Check whether there is no satisfaction path that contains both timelocks and heightlocks.
Node(const Ctx &ctx, Fragment nt, std::vector< Key > key, uint32_t val=0)
Node(const Ctx &ctx, Fragment nt, std::vector< unsigned char > arg, uint32_t val=0)
MiniscriptContext GetMsCtx() const
Return the script context for this node.
const internal::Ops ops
Cached ops counts.
bool IsValid() const
Check whether this node is valid at all.
const std::vector< unsigned char > data
The data bytes in this expression (only for HASH160/HASH256/SHA256/RIPEMD10).
const internal::StackSize ss
Cached stack size bounds.
Availability Satisfy(const Ctx &ctx, std::vector< std::vector< unsigned char > > &stack, bool nonmalleable=true) const
Produce a witness for this script, if possible and given the information available in the context.
Node(internal::NoDupCheck, MiniscriptContext script_ctx, Fragment nt, std::vector< NodeRef< Key > > sub, std::vector< unsigned char > arg, uint32_t val=0)
bool IsSatisfiable(F fn) const
Determine whether a Miniscript node is satisfiable.
Class whose objects represent the maximum of a list of integers.
friend MaxInt< I > operator+(const MaxInt< I > &a, const MaxInt< I > &b)
friend MaxInt< I > operator|(const MaxInt< I > &a, const MaxInt< I > &b)
Ops(uint32_t in_count, MaxInt< uint32_t > in_sat, MaxInt< uint32_t > in_dsat)
MaxInt< uint32_t > sat
Number of keys in possibly executed OP_CHECKMULTISIG(VERIFY)s to satisfy.
MaxInt< uint32_t > dsat
Number of keys in possibly executed OP_CHECKMULTISIG(VERIFY)s to dissatisfy.
uint32_t count
Non-push opcodes.
A data structure to help the calculation of stack size limits.
static constexpr SatInfo Nop() noexcept
A script consisting of just a repurposed nop (OP_CHECKLOCKTIMEVERIFY, OP_CHECKSEQUENCEVERIFY).
const int32_t exec
Mow much higher the stack size can be during execution compared to at the end.
static constexpr SatInfo OP_CHECKSIG() noexcept
static constexpr SatInfo BinaryOp() noexcept
A script consisting of just a binary operator (OP_BOOLAND, OP_BOOLOR, OP_ADD).
static constexpr SatInfo OP_VERIFY() noexcept
static constexpr SatInfo Push() noexcept
A script consisting of a single push opcode.
static constexpr SatInfo Empty() noexcept
The empty script.
constexpr SatInfo(int32_t in_netdiff, int32_t in_exec) noexcept
Script set with a single script in it, with specified netdiff and exec.
constexpr friend SatInfo operator|(const SatInfo &a, const SatInfo &b) noexcept
Script set union.
const int32_t netdiff
How much higher the stack size at start of execution can be compared to at the end.
constexpr SatInfo() noexcept
Empty script set.
static constexpr SatInfo OP_EQUALVERIFY() noexcept
static constexpr SatInfo OP_IFDUP(bool nonzero) noexcept
const bool valid
Whether a canonical satisfaction/dissatisfaction is possible at all.
static constexpr SatInfo OP_DUP() noexcept
static constexpr SatInfo OP_0NOTEQUAL() noexcept
static constexpr SatInfo If() noexcept
A script consisting of just OP_IF or OP_NOTIF.
static constexpr SatInfo OP_EQUAL() noexcept
static constexpr SatInfo OP_SIZE() noexcept
static constexpr SatInfo Hash() noexcept
A script consisting of a single hash opcode.
constexpr friend SatInfo operator+(const SatInfo &a, const SatInfo &b) noexcept
Script set concatenation.
constexpr StackSize(SatInfo in_both) noexcept
constexpr StackSize(SatInfo in_sat, SatInfo in_dsat) noexcept
MaxInt< uint32_t > sat
Maximum witness size to satisfy;.
MaxInt< uint32_t > dsat
Maximum witness size to dissatisfy;.
WitnessSize(MaxInt< uint32_t > in_sat, MaxInt< uint32_t > in_dsat)
static const std::vector< uint8_t > EMPTY
bool IsHex(std::string_view str)
std::vector< typename std::common_type< Args... >::type > Vector(Args &&... args)
Construct a vector with the specified elements.