5 #ifndef BITCOIN_SCRIPT_MINISCRIPT_H 6 #define BITCOIN_SCRIPT_MINISCRIPT_H 157 inline consteval
Type operator""_mst(
const char* c,
size_t l)
161 for (
const char *p = c; p < c + l; p++) {
173 *p ==
'f' ? 1 << 10 :
174 *p ==
's' ? 1 << 11 :
175 *p ==
'm' ? 1 << 12 :
176 *p ==
'x' ? 1 << 13 :
177 *p ==
'g' ? 1 << 14 :
178 *p ==
'h' ? 1 << 15 :
179 *p ==
'i' ? 1 << 16 :
180 *p ==
'j' ? 1 << 17 :
181 *p ==
'k' ? 1 << 18 :
182 (
throw std::logic_error(
"Unknown character in _mst literal"), 0)
189 using Opcode = std::pair<opcodetype, std::vector<unsigned char>>;
191 template<
typename Key>
struct Node;
192 template<
typename Key>
using NodeRef = std::unique_ptr<const Node<Key>>;
195 template<
typename Key,
typename... Args>
311 std::vector<std::vector<unsigned char>>
stack;
345 template<
typename A,
typename B>
364 if (!a.
valid)
return b;
365 if (!b.
valid)
return a;
434 constexpr
SatInfo(int32_t in_netdiff, int32_t in_exec) noexcept :
441 if (!a.valid)
return b;
442 if (!b.valid)
return a;
444 return {std::max(a.netdiff, b.netdiff), std::max(a.exec, b.exec)};
451 if (!a.valid || !b.valid)
return {};
455 return {a.
netdiff + b.netdiff, std::max(b.exec, b.netdiff + a.exec)};
467 static constexpr
SatInfo If() noexcept {
return {1, 1}; }
473 static constexpr
SatInfo OP_IFDUP(
bool nonzero) noexcept {
return {nonzero ? -1 : 0, 0}; }
503 template<
typename Key>
508 const uint32_t
k = 0;
512 const std::vector<unsigned char>
data;
514 mutable std::vector<NodeRef<Key>>
subs;
521 while (!
subs.empty()) {
524 while (!
node->subs.empty()) {
525 subs.push_back(std::move(
node->subs.back()));
526 node->subs.pop_back();
535 std::vector<NodeRef<Key>> new_subs;
536 for (
auto child = children.begin(); child != children.end(); ++child) {
537 new_subs.emplace_back(std::move(*child));
542 return TreeEval<NodeRef<Key>>(upfn);
567 :
fragment(nt),
k(val),
keys(key),
data(
std::move(arg)),
subs(
std::move(sub)),
m_script_ctx{script_ctx},
ops(
CalcOps()),
ss(
CalcStackSize()),
ws(
CalcWitnessSize()),
typ(
CalcType()),
scriptlen(
CalcScriptLen()) {}
572 for (
const auto& sub :
subs) {
573 subsize += sub->ScriptSize();
575 static constexpr
auto NONE_MST{
""_mst};
576 Type sub0type =
subs.size() > 0 ?
subs[0]->GetType() : NONE_MST;
603 template<
typename Result,
typename State,
typename DownFn,
typename UpFn>
613 StackElem(
const Node& node_,
size_t exp_,
State&& state_) :
614 node(node_), expanded(exp_), state(std::move(state_)) {}
617 std::vector<StackElem> stack;
620 std::vector<Result> results;
621 stack.emplace_back(*
this, 0, std::move(root_state));
639 while (stack.size()) {
640 const Node&
node = stack.back().node;
641 if (stack.back().expanded <
node.subs.size()) {
645 size_t child_index = stack.back().expanded++;
646 State child_state = downfn(stack.back().state,
node, child_index);
647 stack.emplace_back(*
node.subs[child_index], 0, std::move(child_state));
652 std::optional<Result>
result{upfn(std::move(stack.back().state),
node,
657 results.erase(results.end() -
node.subs.size(), results.end());
658 results.push_back(std::move(*
result));
662 assert(results.size() == 1);
663 return std::move(results[0]);
668 template<
typename Result,
typename UpFn>
671 struct DummyState {};
672 return TreeEvalMaybe<Result>(DummyState{},
673 [](DummyState,
const Node&, size_t) {
return DummyState{}; },
681 template<
typename Result,
typename State,
typename DownFn,
typename UpFn>
686 return std::move(*TreeEvalMaybe<Result>(std::move(root_state),
687 std::forward<DownFn>(downfn),
690 return std::optional<Result>(std::move(res));
697 template<
typename Result,
typename UpFn>
700 struct DummyState {};
701 return std::move(*TreeEvalMaybe<Result>(DummyState{},
702 [](DummyState,
const Node&, size_t) {
return DummyState{}; },
705 return std::optional<Result>(std::move(res));
713 std::vector<std::pair<const Node<Key>&,
const Node<Key>&>> queue;
714 queue.emplace_back(node1, node2);
715 while (!queue.empty()) {
716 const auto& [a, b] = queue.back();
718 if (std::tie(a.fragment, a.k, a.keys, a.data) < std::tie(b.fragment, b.k, b.keys, b.data))
return -1;
719 if (std::tie(b.fragment, b.k, b.keys, b.data) < std::tie(a.fragment, a.k, a.keys, a.data))
return 1;
720 if (a.subs.size() < b.subs.size())
return -1;
721 if (b.subs.size() < a.subs.size())
return 1;
722 size_t n = a.
subs.size();
723 for (
size_t i = 0; i < n; ++i) {
724 queue.emplace_back(*a.subs[n - 1 - i], *b.subs[n - 1 - i]);
732 using namespace internal;
735 std::vector<Type> sub_types;
737 for (
const auto& sub :
subs) sub_types.push_back(sub->GetType());
740 static constexpr
auto NONE_MST{
""_mst};
741 Type x =
subs.size() > 0 ?
subs[0]->GetType() : NONE_MST;
742 Type y =
subs.size() > 1 ?
subs[1]->GetType() : NONE_MST;
743 Type z =
subs.size() > 2 ?
subs[2]->GetType() : NONE_MST;
749 template<
typename Ctx>
768 switch (
node.fragment) {
782 if (
node.subs[0]->GetType() <<
"x"_mst) {
785 return std::move(
subs[0]);
802 for (
const auto& key :
node.keys) {
810 for (
auto it =
node.keys.begin() + 1; it !=
node.keys.end(); ++it) {
817 for (
size_t i = 1; i <
subs.size(); ++i) {
825 return TreeEval<CScript>(
false, downfn, upfn);
828 template<
typename CTx>
829 std::optional<std::string>
ToString(
const CTx& ctx)
const {
833 auto downfn = [](bool,
const Node&
node, size_t) {
846 std::string
ret = wrapped ?
":" :
"";
848 switch (
node.fragment) {
854 auto key_str = ctx.ToString(
node.subs[0]->keys[0]);
855 if (!key_str)
return {};
856 return std::move(
ret) +
"pk(" + std::move(*key_str) +
")";
860 auto key_str = ctx.ToString(
node.subs[0]->keys[0]);
861 if (!key_str)
return {};
862 return std::move(
ret) +
"pkh(" + std::move(*key_str) +
")";
864 return "c" + std::move(
subs[0]);
879 switch (
node.fragment) {
881 auto key_str = ctx.ToString(
node.keys[0]);
882 if (!key_str)
return {};
883 return std::move(
ret) +
"pk_k(" + std::move(*key_str) +
")";
886 auto key_str = ctx.ToString(
node.keys[0]);
887 if (!key_str)
return {};
888 return std::move(
ret) +
"pk_h(" + std::move(*key_str) +
")";
907 return std::move(
ret) +
"andor(" + std::move(
subs[0]) +
"," + std::move(
subs[1]) +
"," + std::move(
subs[2]) +
")";
911 for (
const auto& key :
node.keys) {
912 auto key_str = ctx.ToString(key);
913 if (!key_str)
return {};
914 str +=
"," + std::move(*key_str);
916 return std::move(str) +
")";
921 for (
const auto& key :
node.keys) {
922 auto key_str = ctx.ToString(key);
923 if (!key_str)
return {};
924 str +=
"," + std::move(*key_str);
926 return std::move(str) +
")";
930 for (
auto& sub :
subs) {
931 str +=
"," + std::move(sub);
933 return std::move(str) +
")";
940 return TreeEvalMaybe<std::string>(
false, downfn, upfn);
958 const auto count{1 +
subs[0]->ops.count +
subs[1]->ops.count};
959 const auto sat{
subs[0]->ops.sat +
subs[1]->ops.sat};
960 const auto dsat{
subs[0]->ops.dsat +
subs[1]->ops.dsat};
961 return {
count, sat, dsat};
964 const auto count{1 +
subs[0]->ops.count +
subs[1]->ops.count};
966 const auto dsat{
subs[0]->ops.dsat +
subs[1]->ops.dsat};
967 return {
count, sat, dsat};
970 const auto count{3 +
subs[0]->ops.count +
subs[1]->ops.count};
971 const auto sat{
subs[0]->ops.sat | (
subs[1]->ops.sat +
subs[0]->ops.dsat)};
972 const auto dsat{
subs[0]->ops.dsat +
subs[1]->ops.dsat};
973 return {
count, sat, dsat};
976 const auto count{2 +
subs[0]->ops.count +
subs[1]->ops.count};
977 const auto sat{
subs[0]->ops.sat | (
subs[1]->ops.sat +
subs[0]->ops.dsat)};
978 return {
count, sat, {}};
981 const auto count{3 +
subs[0]->ops.count +
subs[1]->ops.count};
982 const auto sat{
subs[0]->ops.sat |
subs[1]->ops.sat};
983 const auto dsat{
subs[0]->ops.dsat |
subs[1]->ops.dsat};
984 return {
count, sat, dsat};
987 const auto count{3 +
subs[0]->ops.count +
subs[1]->ops.count +
subs[2]->ops.count};
989 const auto dsat{
subs[0]->ops.dsat +
subs[2]->ops.dsat};
990 return {
count, sat, dsat};
1004 for (
const auto& sub :
subs) {
1005 count += sub->ops.count + 1;
1006 auto next_sats =
Vector(sats[0] + sub->ops.dsat);
1007 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub->ops.dsat) | (sats[j - 1] + sub->ops.sat));
1008 next_sats.push_back(sats[sats.size() - 1] + sub->ops.sat);
1009 sats = std::move(next_sats);
1012 return {
count, sats[
k], sats[0]};
1019 using namespace internal;
1035 const auto& x{
subs[0]->ss};
1036 const auto& y{
subs[1]->ss};
1037 const auto& z{
subs[2]->ss};
1039 (x.sat + SatInfo::If() + y.sat) | (x.dsat + SatInfo::If() + z.sat),
1040 x.dsat + SatInfo::If() + z.dsat
1044 const auto& x{
subs[0]->ss};
1045 const auto& y{
subs[1]->ss};
1046 return {x.sat + y.sat, {}};
1049 const auto& x{
subs[0]->ss};
1050 const auto& y{
subs[1]->ss};
1051 return {x.sat + y.sat + SatInfo::BinaryOp(), x.dsat + y.dsat + SatInfo::BinaryOp()};
1054 const auto& x{
subs[0]->ss};
1055 const auto& y{
subs[1]->ss};
1057 ((x.sat + y.dsat) | (x.dsat + y.sat)) + SatInfo::BinaryOp(),
1058 x.dsat + y.dsat + SatInfo::BinaryOp()
1062 const auto& x{
subs[0]->ss};
1063 const auto& y{
subs[1]->ss};
1064 return {(x.sat + SatInfo::If()) | (x.dsat + SatInfo::If() + y.sat), {}};
1067 const auto& x{
subs[0]->ss};
1068 const auto& y{
subs[1]->ss};
1075 const auto& x{
subs[0]->ss};
1076 const auto& y{
subs[1]->ss};
1077 return {SatInfo::If() + (x.sat | y.sat), SatInfo::If() + (x.dsat | y.dsat)};
1106 auto sats =
Vector(SatInfo::Empty());
1107 for (
size_t i = 0; i <
subs.size(); ++i) {
1110 auto add = i ? SatInfo::BinaryOp() : SatInfo::Empty();
1114 for (
size_t j = 1; j < sats.size(); ++j) {
1115 next_sats.push_back(((sats[j] +
subs[i]->
ss.
dsat) | (sats[j - 1] +
subs[i]->ss.sat)) + add);
1118 next_sats.push_back(sats[sats.size() - 1] +
subs[i]->ss.sat + add);
1120 sats = std::move(next_sats);
1149 const auto dsat{
subs[0]->ws.dsat +
subs[2]->ws.dsat};
1156 const auto dsat{
subs[0]->ws.dsat +
subs[1]->ws.dsat};
1173 for (
const auto& sub :
subs) {
1174 auto next_sats =
Vector(sats[0] + sub->ws.dsat);
1175 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub->ws.dsat) | (sats[j - 1] + sub->ws.sat));
1176 next_sats.push_back(sats[sats.size() - 1] + sub->ws.sat);
1177 sats = std::move(next_sats);
1180 return {sats[
k], sats[0]};
1186 template<
typename Ctx>
1188 using namespace internal;
1193 switch (
node.fragment) {
1195 std::vector<unsigned char> sig;
1197 return {
ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
1200 std::vector<unsigned char> key = ctx.ToPKBytes(
node.keys[0]), sig;
1202 return {
ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
1208 for (
size_t i = 0; i <
node.keys.size(); ++i) {
1211 std::vector<unsigned char> sig;
1214 auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1218 std::vector<InputStack> next_sats;
1219 next_sats.push_back(sats[0] +
ZERO);
1220 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] +
ZERO) | (std::move(sats[j - 1]) + sat));
1221 next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1223 sats = std::move(next_sats);
1227 auto& nsat{sats[0]};
1230 return {std::move(nsat), std::move(sats[
node.k])};
1237 for (
size_t i = 0; i <
node.keys.size(); ++i) {
1238 std::vector<unsigned char> sig;
1241 auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1245 std::vector<InputStack> next_sats;
1246 next_sats.push_back(sats[0]);
1247 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
1248 next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1250 sats = std::move(next_sats);
1253 InputStack nsat =
ZERO;
1254 for (
size_t i = 0; i <
node.k; ++i) nsat = std::move(nsat) +
ZERO;
1256 return {std::move(nsat), std::move(sats[
node.k])};
1263 for (
size_t i = 0; i < subres.size(); ++i) {
1265 auto& res = subres[subres.size() - i - 1];
1269 std::vector<InputStack> next_sats;
1270 next_sats.push_back(sats[0] + res.nsat);
1271 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + res.nsat) | (std::move(sats[j - 1]) + res.sat));
1272 next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
1274 sats = std::move(next_sats);
1278 InputStack nsat = INVALID;
1279 for (
size_t i = 0; i < sats.size(); ++i) {
1286 if (i != 0 && i !=
node.k) sats[i].SetMalleable().SetNonCanon();
1288 if (i !=
node.k) nsat = std::move(nsat) | std::move(sats[i]);
1291 return {std::move(nsat), std::move(sats[
node.k])};
1294 return {INVALID, ctx.CheckOlder(
node.k) ?
EMPTY : INVALID};
1297 return {INVALID, ctx.CheckAfter(
node.k) ?
EMPTY : INVALID};
1300 std::vector<unsigned char> preimage;
1302 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1305 std::vector<unsigned char> preimage;
1307 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1310 std::vector<unsigned char> preimage;
1312 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1315 std::vector<unsigned char> preimage;
1317 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1320 auto& x = subres[0], &y = subres[1];
1327 return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
1330 auto& x = subres[0], &y = subres[1];
1336 return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
1339 auto& x = subres[0], &z = subres[1];
1341 return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
1344 auto& x = subres[0], &z = subres[1];
1345 return {INVALID, std::move(x.sat) | (z.sat + x.nsat)};
1348 auto& x = subres[0], &z = subres[1];
1349 return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
1352 auto& x = subres[0], &z = subres[1];
1353 return {(x.nsat +
ONE) | (z.nsat +
ZERO), (x.sat +
ONE) | (z.sat +
ZERO)};
1356 auto& x = subres[0], &y = subres[1], &z = subres[2];
1357 return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
1363 return std::move(subres[0]);
1365 auto &x = subres[0];
1369 auto &x = subres[0];
1375 return {InputStack(
ZERO).SetMalleable(x.nsat.available !=
Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
1378 auto &x = subres[0];
1379 return {INVALID, std::move(x.sat)};
1385 return {INVALID, INVALID};
1389 auto ret = helper(
node, subres);
1412 if (
node.GetType() <<
"d"_mst && !
ret.nsat.malleable)
assert(!
ret.nsat.non_canon);
1420 if (
node.GetType() <<
"me"_mst)
assert(!
ret.nsat.malleable);
1431 return TreeEval<InputResult>(tester);
1446 Comp(
const Ctx& ctx) : ctx_ptr(&ctx) {}
1447 bool operator()(
const Key& a,
const Key& b)
const {
return ctx_ptr->KeyCompare(a, b); }
1453 using keyset = std::set<Key, Comp>;
1454 using state = std::optional<keyset>;
1458 if (
node.has_duplicate_keys.has_value() && *
node.has_duplicate_keys)
return {};
1461 for (
auto& sub :
subs) {
1462 if (!sub.has_value()) {
1463 node.has_duplicate_keys =
true;
1470 size_t keys_count =
node.keys.size();
1471 keyset key_set{
node.keys.begin(),
node.keys.end(), Comp(ctx)};
1472 if (key_set.size() != keys_count) {
1474 node.has_duplicate_keys =
true;
1479 for (
auto& sub :
subs) {
1480 keys_count += sub->size();
1483 if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1484 key_set.merge(*sub);
1485 if (key_set.size() != keys_count) {
1486 node.has_duplicate_keys =
true;
1491 node.has_duplicate_keys =
false;
1495 TreeEval<state>(upfn);
1519 return !((
GetType() &
"BKW"_mst) ==
""_mst);
1565 for (
auto& sub:
subs)
if (sub)
return sub;
1566 if (!
node.IsSaneSubexpression())
return &
node;
1573 template<
typename F>
1578 switch (
node.fragment) {
1593 return bool{fn(
node)};
1615 if (
GetType() ==
""_mst)
return false;
1647 template<
typename Ctx>
1648 Availability Satisfy(
const Ctx& ctx, std::vector<std::vector<unsigned char>>& stack,
bool nonmalleable =
true)
const {
1651 stack = std::move(
ret.sat.stack);
1652 return ret.sat.available;
1673 template <
typename Ctx>
Node(
const Ctx& ctx,
Fragment nt, std::vector<
NodeRef<Key>> sub, std::vector<unsigned char> arg, uint32_t val = 0)
1674 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt, std::move(sub), std::move(arg), val) {
DuplicateKeyCheck(ctx); }
1675 template <
typename Ctx>
Node(
const Ctx& ctx,
Fragment nt, std::vector<unsigned char> arg, uint32_t val = 0)
1678 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt, std::move(sub), std::move(key), val) {
DuplicateKeyCheck(ctx); }
1679 template <
typename Ctx>
Node(
const Ctx& ctx,
Fragment nt, std::vector<Key> key, uint32_t val = 0)
1680 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt, std::move(key), val) {
DuplicateKeyCheck(ctx); }
1682 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt, std::move(sub), val) {
DuplicateKeyCheck(ctx); }
1683 template <
typename Ctx>
Node(
const Ctx& ctx,
Fragment nt, uint32_t val = 0)
1691 namespace internal {
1750 template<
typename Key,
typename Ctx>
1754 if (key_size < 1)
return {};
1755 auto key = ctx.FromString(in.
begin(), in.
begin() + key_size);
1756 if (!key)
return {};
1757 return {{std::move(*key), key_size}};
1761 template<
typename Ctx>
1766 if (hash_size < 1)
return {};
1767 std::string val = std::string(in.
begin(), in.
begin() + hash_size);
1768 if (!
IsHex(val))
return {};
1770 if (hash.size() != expected_size)
return {};
1771 return {{std::move(hash), hash_size}};
1775 template<
typename Key>
1779 constructed.pop_back();
1781 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, script_ctx, nt,
Vector(std::move(child), std::move(constructed.back())));
1783 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, script_ctx, nt,
Vector(std::move(constructed.back()), std::move(child)));
1792 template<
typename Key,
typename Ctx>
1807 size_t script_size{1};
1811 std::vector<std::tuple<ParseContext, int64_t, int64_t>> to_parse;
1812 std::vector<NodeRef<Key>> constructed;
1814 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
1817 const auto parse_multi_exp = [&](
Span<const char>& in,
const bool is_multi_a) ->
bool {
1820 if (ctx.MsContext() != required_ctx)
return false;
1823 if (next_comma < 1)
return false;
1824 const auto k_to_integral{ToIntegral<int64_t>(std::string_view(in.
data(), next_comma))};
1825 if (!k_to_integral.has_value())
return false;
1826 const int64_t
k{k_to_integral.value()};
1827 in = in.
subspan(next_comma + 1);
1829 std::vector<Key>
keys;
1830 while (next_comma != -1) {
1832 int key_length = (next_comma == -1) ?
FindNextChar(in,
')') : next_comma;
1833 if (key_length < 1)
return false;
1834 auto key = ctx.FromString(in.
begin(), in.
begin() + key_length);
1835 if (!key)
return false;
1836 keys.push_back(std::move(*key));
1837 in = in.
subspan(key_length + 1);
1839 if (
keys.size() < 1 ||
keys.size() > max_keys)
return false;
1840 if (k < 1 || k > (int64_t)
keys.size())
return false;
1846 script_size += 2 + (
keys.size() > 16) + (
k > 16) + 34 *
keys.size();
1852 while (!to_parse.empty()) {
1853 if (script_size > max_size)
return {};
1856 auto [cur_context, n,
k] = to_parse.back();
1857 to_parse.pop_back();
1859 switch (cur_context) {
1860 case ParseContext::WRAPPED_EXPR: {
1861 std::optional<size_t> colon_index{};
1862 for (
size_t i = 1; i < in.
size(); ++i) {
1867 if (in[i] <
'a' || in[i] >
'z')
break;
1870 bool last_was_v{
false};
1871 for (
size_t j = 0; colon_index && j < *colon_index; ++j) {
1872 if (script_size > max_size)
return {};
1875 to_parse.emplace_back(ParseContext::ALT, -1, -1);
1876 }
else if (in[j] ==
's') {
1878 to_parse.emplace_back(ParseContext::SWAP, -1, -1);
1879 }
else if (in[j] ==
'c') {
1882 }
else if (in[j] ==
'd') {
1884 to_parse.emplace_back(ParseContext::DUP_IF, -1, -1);
1885 }
else if (in[j] ==
'j') {
1887 to_parse.emplace_back(ParseContext::NON_ZERO, -1, -1);
1888 }
else if (in[j] ==
'n') {
1890 to_parse.emplace_back(ParseContext::ZERO_NOTEQUAL, -1, -1);
1891 }
else if (in[j] ==
'v') {
1894 if (last_was_v)
return {};
1895 to_parse.emplace_back(ParseContext::VERIFY, -1, -1);
1896 }
else if (in[j] ==
'u') {
1898 to_parse.emplace_back(ParseContext::WRAP_U, -1, -1);
1899 }
else if (in[j] ==
't') {
1901 to_parse.emplace_back(ParseContext::WRAP_T, -1, -1);
1902 }
else if (in[j] ==
'l') {
1910 last_was_v = (in[j] ==
'v');
1912 to_parse.emplace_back(ParseContext::EXPR, -1, -1);
1913 if (colon_index) in = in.
subspan(*colon_index + 1);
1916 case ParseContext::EXPR: {
1917 if (
Const(
"0", in)) {
1919 }
else if (
Const(
"1", in)) {
1921 }
else if (
Const(
"pk(", in)) {
1922 auto res = ParseKeyEnd<Key, Ctx>(in, ctx);
1923 if (!res)
return {};
1924 auto& [key, key_size] = *res;
1926 in = in.subspan(key_size + 1);
1927 script_size +=
IsTapscript(ctx.MsContext()) ? 33 : 34;
1928 }
else if (
Const(
"pkh(", in)) {
1929 auto res = ParseKeyEnd<Key>(in, ctx);
1930 if (!res)
return {};
1931 auto& [key, key_size] = *res;
1933 in = in.subspan(key_size + 1);
1935 }
else if (
Const(
"pk_k(", in)) {
1936 auto res = ParseKeyEnd<Key>(in, ctx);
1937 if (!res)
return {};
1938 auto& [key, key_size] = *res;
1940 in = in.subspan(key_size + 1);
1941 script_size +=
IsTapscript(ctx.MsContext()) ? 32 : 33;
1942 }
else if (
Const(
"pk_h(", in)) {
1943 auto res = ParseKeyEnd<Key>(in, ctx);
1944 if (!res)
return {};
1945 auto& [key, key_size] = *res;
1947 in = in.subspan(key_size + 1);
1949 }
else if (
Const(
"sha256(", in)) {
1951 if (!res)
return {};
1952 auto& [hash, hash_size] = *res;
1954 in = in.
subspan(hash_size + 1);
1956 }
else if (
Const(
"ripemd160(", in)) {
1958 if (!res)
return {};
1959 auto& [hash, hash_size] = *res;
1961 in = in.
subspan(hash_size + 1);
1963 }
else if (
Const(
"hash256(", in)) {
1965 if (!res)
return {};
1966 auto& [hash, hash_size] = *res;
1968 in = in.
subspan(hash_size + 1);
1970 }
else if (
Const(
"hash160(", in)) {
1972 if (!res)
return {};
1973 auto& [hash, hash_size] = *res;
1975 in = in.
subspan(hash_size + 1);
1977 }
else if (
Const(
"after(", in)) {
1979 if (arg_size < 1)
return {};
1980 const auto num{ToIntegral<int64_t>(std::string_view(in.
data(), arg_size))};
1981 if (!num.has_value() || *num < 1 || *num >= 0x80000000L)
return {};
1983 in = in.
subspan(arg_size + 1);
1984 script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
1985 }
else if (
Const(
"older(", in)) {
1987 if (arg_size < 1)
return {};
1988 const auto num{ToIntegral<int64_t>(std::string_view(in.
data(), arg_size))};
1989 if (!num.has_value() || *num < 1 || *num >= 0x80000000L)
return {};
1991 in = in.
subspan(arg_size + 1);
1992 script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
1993 }
else if (
Const(
"multi(", in)) {
1994 if (!parse_multi_exp(in,
false))
return {};
1995 }
else if (
Const(
"multi_a(", in)) {
1996 if (!parse_multi_exp(in,
true))
return {};
1997 }
else if (
Const(
"thresh(", in)) {
1999 if (next_comma < 1)
return {};
2000 const auto k{ToIntegral<int64_t>(std::string_view(in.
data(), next_comma))};
2001 if (!
k.has_value() || *
k < 1)
return {};
2002 in = in.
subspan(next_comma + 1);
2005 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2006 script_size += 2 + (*
k > 16) + (*
k > 0x7f) + (*
k > 0x7fff) + (*
k > 0x7fffff);
2007 }
else if (
Const(
"andor(", in)) {
2009 to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
2010 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2011 to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2012 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2013 to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2014 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2017 if (
Const(
"and_n(", in)) {
2018 to_parse.emplace_back(ParseContext::AND_N, -1, -1);
2020 }
else if (
Const(
"and_b(", in)) {
2023 }
else if (
Const(
"and_v(", in)) {
2026 }
else if (
Const(
"or_b(", in)) {
2029 }
else if (
Const(
"or_c(", in)) {
2032 }
else if (
Const(
"or_d(", in)) {
2035 }
else if (
Const(
"or_i(", in)) {
2041 to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
2042 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2043 to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2044 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2048 case ParseContext::ALT: {
2052 case ParseContext::SWAP: {
2060 case ParseContext::DUP_IF: {
2064 case ParseContext::NON_ZERO: {
2068 case ParseContext::ZERO_NOTEQUAL: {
2072 case ParseContext::VERIFY: {
2073 script_size += (constructed.back()->GetType() <<
"x"_mst);
2077 case ParseContext::WRAP_U: {
2081 case ParseContext::WRAP_T: {
2089 case ParseContext::AND_N: {
2090 auto mid = std::move(constructed.back());
2091 constructed.pop_back();
2116 auto right = std::move(constructed.back());
2117 constructed.pop_back();
2118 auto mid = std::move(constructed.back());
2119 constructed.pop_back();
2124 if (in.
size() < 1)
return {};
2128 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2130 }
else if (in[0] ==
')') {
2131 if (
k > n)
return {};
2134 std::vector<NodeRef<Key>>
subs;
2135 for (
int i = 0; i < n; ++i) {
2136 subs.push_back(std::move(constructed.back()));
2137 constructed.pop_back();
2139 std::reverse(
subs.begin(),
subs.end());
2146 case ParseContext::COMMA: {
2147 if (in.
size() < 1 || in[0] !=
',')
return {};
2151 case ParseContext::CLOSE_BRACKET: {
2152 if (in.
size() < 1 || in[0] !=
')')
return {};
2160 assert(constructed.size() == 1);
2162 if (in.
size() > 0)
return {};
2164 tl_node->DuplicateKeyCheck(ctx);
2250 template<
typename Key,
typename Ctx,
typename I>
2254 std::vector<std::tuple<DecodeContext, int64_t, int64_t>> to_parse;
2255 std::vector<NodeRef<Key>> constructed;
2259 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2261 while (!to_parse.empty()) {
2263 if (!constructed.empty() && !constructed.back()->IsValid())
return {};
2266 auto [cur_context, n,
k] = to_parse.back();
2267 to_parse.pop_back();
2269 switch(cur_context) {
2270 case DecodeContext::SINGLE_BKV_EXPR: {
2271 if (in >= last)
return {};
2274 if (in[0].first ==
OP_1) {
2279 if (in[0].first ==
OP_0) {
2285 if (in[0].second.size() == 33 || in[0].second.size() == 32) {
2286 auto key = ctx.FromPKBytes(in[0].second.begin(), in[0].second.end());
2287 if (!key)
return {};
2293 auto key = ctx.FromPKHBytes(in[2].second.begin(), in[2].second.end());
2294 if (!key)
return {};
2300 std::optional<int64_t> num;
2303 if (*num < 1 || *num > 0x7FFFFFFFL)
return {};
2309 if (num < 1 || num > 0x7FFFFFFFL)
return {};
2315 if (in[2].first ==
OP_SHA256 && in[1].second.size() == 32) {
2319 }
else if (in[2].first ==
OP_RIPEMD160 && in[1].second.size() == 20) {
2323 }
else if (in[2].first ==
OP_HASH256 && in[1].second.size() == 32) {
2327 }
else if (in[2].first ==
OP_HASH160 && in[1].second.size() == 20) {
2336 std::vector<Key>
keys;
2338 if (!n || last - in < 3 + *n)
return {};
2339 if (*n < 1 || *n > 20)
return {};
2340 for (
int i = 0; i < *n; ++i) {
2341 if (in[2 + i].second.size() != 33)
return {};
2342 auto key = ctx.FromPKBytes(in[2 + i].second.begin(), in[2 + i].second.end());
2343 if (!key)
return {};
2344 keys.push_back(std::move(*key));
2347 if (!
k || *k < 1 || *k > *n)
return {};
2349 std::reverse(
keys.begin(),
keys.end());
2354 if (last - in >= 4 && in[0].first ==
OP_NUMEQUAL) {
2360 if (last - in < 2 + *
k * 2)
return {};
2361 std::vector<Key>
keys;
2364 for (
int pos = 2;; pos += 2) {
2365 if (last - in < pos + 2)
return {};
2368 if (in[pos + 1].second.size() != 32)
return {};
2369 auto key = ctx.FromPKBytes(in[pos + 1].second.begin(), in[pos + 1].second.end());
2370 if (!key)
return {};
2371 keys.push_back(std::move(*key));
2377 if (
keys.size() < (size_t)*
k)
return {};
2378 in += 2 +
keys.size() * 2;
2379 std::reverse(
keys.begin(),
keys.end());
2390 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2396 to_parse.emplace_back(DecodeContext::VERIFY, -1, -1);
2397 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2403 to_parse.emplace_back(DecodeContext::ZERO_NOTEQUAL, -1, -1);
2404 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2409 if (*num < 1)
return {};
2411 to_parse.emplace_back(DecodeContext::THRESH_W, 0, *num);
2417 to_parse.emplace_back(DecodeContext::ENDIF, -1, -1);
2418 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2430 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2431 to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2438 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2439 to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2445 case DecodeContext::BKV_EXPR: {
2446 to_parse.emplace_back(DecodeContext::MAYBE_AND_V, -1, -1);
2447 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2450 case DecodeContext::W_EXPR: {
2452 if (in >= last)
return {};
2455 to_parse.emplace_back(DecodeContext::ALT, -1, -1);
2457 to_parse.emplace_back(DecodeContext::SWAP, -1, -1);
2459 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2462 case DecodeContext::MAYBE_AND_V: {
2468 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2472 case DecodeContext::SWAP: {
2473 if (in >= last || in[0].first !=
OP_SWAP || constructed.empty())
return {};
2478 case DecodeContext::ALT: {
2479 if (in >= last || in[0].first !=
OP_TOALTSTACK || constructed.empty())
return {};
2485 if (constructed.empty())
return {};
2489 case DecodeContext::DUP_IF: {
2490 if (constructed.empty())
return {};
2494 case DecodeContext::VERIFY: {
2495 if (constructed.empty())
return {};
2499 case DecodeContext::NON_ZERO: {
2500 if (constructed.empty())
return {};
2504 case DecodeContext::ZERO_NOTEQUAL: {
2505 if (constructed.empty())
return {};
2510 if (constructed.size() < 2)
return {};
2515 if (constructed.size() < 2)
return {};
2520 if (constructed.size() < 2)
return {};
2525 if (constructed.size() < 2)
return {};
2530 if (constructed.size() < 2)
return {};
2535 if (constructed.size() < 3)
return {};
2537 constructed.pop_back();
2539 constructed.pop_back();
2544 case DecodeContext::THRESH_W: {
2545 if (in >= last)
return {};
2546 if (in[0].first ==
OP_ADD) {
2548 to_parse.emplace_back(DecodeContext::THRESH_W, n+1,
k);
2549 to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2551 to_parse.emplace_back(DecodeContext::THRESH_E, n+1,
k);
2553 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2557 case DecodeContext::THRESH_E: {
2558 if (k < 1 || k > n || constructed.size() <
static_cast<size_t>(n))
return {};
2559 std::vector<NodeRef<Key>>
subs;
2560 for (
int i = 0; i < n; ++i) {
2562 constructed.pop_back();
2563 subs.push_back(std::move(sub));
2568 case DecodeContext::ENDIF: {
2569 if (in >= last)
return {};
2574 to_parse.emplace_back(DecodeContext::ENDIF_ELSE, -1, -1);
2575 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2578 else if (in[0].first ==
OP_IF) {
2579 if (last - in >= 2 && in[1].first ==
OP_DUP) {
2581 to_parse.emplace_back(DecodeContext::DUP_IF, -1, -1);
2584 to_parse.emplace_back(DecodeContext::NON_ZERO, -1, -1);
2590 }
else if (in[0].first ==
OP_NOTIF) {
2592 to_parse.emplace_back(DecodeContext::ENDIF_NOTIF, -1, -1);
2599 case DecodeContext::ENDIF_NOTIF: {
2600 if (in >= last)
return {};
2608 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2611 case DecodeContext::ENDIF_ELSE: {
2612 if (in >= last)
return {};
2613 if (in[0].first ==
OP_IF) {
2616 }
else if (in[0].first ==
OP_NOTIF) {
2620 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2628 if (constructed.size() != 1)
return {};
2630 tl_node->DuplicateKeyCheck(ctx);
2633 if (!tl_node->IsValidTopLevel())
return {};
2639 template<
typename Ctx>
2641 return internal::Parse<typename Ctx::Key>(str, ctx);
2644 template<
typename Ctx>
2646 using namespace internal;
2650 if (!decomposed)
return {};
2651 auto it = decomposed->begin();
2652 auto ret = DecodeScript<typename Ctx::Key>(it, decomposed->end(), ctx);
2653 if (!
ret)
return {};
2654 if (it != decomposed->end())
return {};
2660 #endif // BITCOIN_SCRIPT_MINISCRIPT_H CScript BuildScript(Ts &&... inputs)
Build a script by concatenating other scripts, or any argument accepted by CScript::operator<<.
OP_SIZE 32 OP_EQUALVERIFY OP_HASH160 [hash] OP_EQUAL.
Node(internal::NoDupCheck, MiniscriptContext script_ctx, Fragment nt, std::vector< unsigned char > arg, uint32_t val=0)
NodeRef< typename Ctx::Key > FromString(const std::string &str, const Ctx &ctx)
A node in a miniscript expression.
CONSTEXPR_IF_NOT_DEBUG Span< C > subspan(std::size_t offset) const noexcept
Potentially multiple SINGLE_BKV_EXPRs as children of (potentially multiple) and_v expressions...
[X] OP_VERIFY (or -VERIFY version of last opcode in X)
SWAP wraps the top constructed node with s:
static constexpr SatInfo BinaryOp() noexcept
A script consisting of just a binary operator (OP_BOOLAND, OP_BOOLOR, OP_ADD).
bool IsNotSatisfiable() const
Whether no satisfaction exists for this node.
friend MaxInt< I > operator+(const MaxInt< I > &a, const MaxInt< I > &b)
[X] OP_NOTIF [Z] OP_ELSE [Y] OP_ENDIF
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...
static const auto ZERO32
A stack consisting of a single malleable 32-byte 0x0000...0000 element (for dissatisfying hash challe...
Node(const Ctx &ctx, Fragment nt, std::vector< unsigned char > arg, uint32_t val=0)
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.
const MiniscriptContext m_script_ctx
The Script context for this node. Either P2WSH or Tapscript.
std::vector< Byte > ParseHex(std::string_view hex_str)
Like TryParseHex, but returns an empty vector on invalid input.
static const int WITNESS_SCALE_FACTOR
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.
OP_DUP OP_HASH160 [keyhash] OP_EQUALVERIFY.
ALT wraps the top constructed node with a:
constexpr uint32_t TXIN_BYTES_NO_WITNESS
prevout + nSequence + scriptSig
const std::vector< unsigned char > data
The data bytes in this expression (only for HASH160/HASH256/SHA256/RIPEMD10).
VERIFY wraps the top constructed node with v:
OP_SIZE 32 OP_EQUALVERIFY OP_RIPEMD160 [hash] OP_EQUAL.
const Node * FindInsaneSub() const
Find an insane subnode which has no insane children. Nullptr if there is none.
std::optional< Result > TreeEvalMaybe(UpFn upfn) const
Like TreeEvalMaybe, but without downfn or State type.
[k] [key_n]* [n] OP_CHECKMULTISIG (only available within P2WSH context)
std::optional< Result > TreeEvalMaybe(State root_state, DownFn downfn, UpFn upfn) const
[n] OP_CHECKLOCKTIMEVERIFY
constexpr SatInfo(int32_t in_netdiff, int32_t in_exec) noexcept
Script set with a single script in it, with specified netdiff and exec.
bool CheckDuplicateKey() const
Check whether there is no duplicate key across this fragment and all its sub-fragments.
OP_TOALTSTACK [X] OP_FROMALTSTACK.
const uint32_t k
The k parameter (time for OLDER/AFTER, threshold for THRESH(_M))
#define CHECK_NONFATAL(condition)
Identity function.
constexpr bool IsTapscript(MiniscriptContext ms_ctx)
Whether the context Tapscript, ensuring the only other possibility is P2WSH.
bool IsHex(std::string_view str)
bool IsValid() const
Check whether this node is valid at all.
constexpr std::size_t size() const noexcept
If, inside an ENDIF context, we find an OP_NOTIF before finding an OP_ELSE, we could either be in an ...
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.
static consteval Type Make(uint32_t flags) noexcept
Construction function used by the ""_mst operator.
const internal::WitnessSize ws
Cached witness size bounds.
Type CalcType() const
Compute the type for this miniscript.
static const auto ONE
A stack consisting of a single 0x01 element (interpreted as 1 by the script interpreted in numeric co...
static constexpr SatInfo Nop() noexcept
A script consisting of just a repurposed nop (OP_CHECKLOCKTIMEVERIFY, OP_CHECKSEQUENCEVERIFY).
Node(const Ctx &ctx, Fragment nt, std::vector< NodeRef< Key >> sub, std::vector< Key > key, uint32_t val=0)
WRAP_U will construct an or_i(X,0) node from the top constructed node.
size_t CalcScriptLen() const
Compute the length of the script for this miniscript (including children).
constexpr SatInfo() noexcept
Empty script set.
Ops(uint32_t in_count, MaxInt< uint32_t > in_sat, MaxInt< uint32_t > in_dsat)
ZERO_NOTEQUAL wraps the top constructed node with n:
std::optional< uint32_t > GetWitnessSize() const
Return the maximum size in bytes of a witness to satisfy this script non-malleably.
[X] OP_NOTIF [Y] OP_ENDIF
std::optional< bool > has_duplicate_keys
Whether a public key appears more than once in this node.
WRAP_T will construct an and_v(X,1) node from the top constructed node.
NodeRef< Key > Clone() const
MaxInt< uint32_t > dsat
Maximum witness size to dissatisfy;.
Node & operator=(const Node &)=delete
MaxInt< uint32_t > sat
Maximum witness size to satisfy;.
ENDIF signals that we are inside some sort of OP_IF structure, which could be or_d, or_c, or_i, andor, d:, or j: wrapper, depending on what follows.
bool IsSane() const
Check whether this node is safe as a script on its own.
Node(const Ctx &ctx, Fragment nt, uint32_t val=0)
constexpr Type If(bool x) const
The empty type if x is false, itself otherwise.
NodeRef< Key > DecodeScript(I &in, I last, const Ctx &ctx)
Parse a miniscript from a bitcoin script.
AND_N will construct an andor(X,Y,0) node from the last two constructed nodes.
[X] OP_IFDUP OP_NOTIF [Y] OP_ENDIF
uint32_t GetStaticOps() const
Return the number of ops in the script (not counting the dynamic ones that depend on execution)...
static constexpr SatInfo OP_SIZE() noexcept
const Type typ
Cached expression type (computed by CalcType and fed through SanitizeType).
An expression which may be begin with wrappers followed by a colon.
const size_t scriptlen
Cached script length (computed by CalcScriptLen).
State
The various states a (txhash,peer) pair can be in.
static const int MAX_PUBKEYS_PER_MULTISIG
static constexpr SatInfo OP_0NOTEQUAL() noexcept
CLOSE_BRACKET expects the next element to be ')' and fails if not.
const Fragment fragment
What node type this node is.
std::pair< opcodetype, std::vector< unsigned char > > Opcode
[X1] ([Xn] OP_ADD)* [k] OP_EQUAL
Node(internal::NoDupCheck, MiniscriptContext script_ctx, Fragment nt, uint32_t val=0)
internal::InputResult ProduceInput(const Ctx &ctx) const
std::vector< typename std::common_type< Args... >::type > Vector(Args &&... args)
Construct a vector with the specified elements.
const int32_t netdiff
How much higher the stack size at start of execution can be compared to at the end.
const int32_t exec
Mow much higher the stack size can be during execution compared to at the end.
int FindNextChar(Span< const char > sp, const char m)
uint32_t count
Non-push opcodes.
constexpr bool operator==(Type x) const
Equality operator.
constexpr StackSize(SatInfo in_both) noexcept
A single expression of type B, K, or V.
In a thresh expression, all sub-expressions other than the first are W-type, and end in OP_ADD...
uint32_t m_flags
Internal bitmap of properties (see ""_mst operator for details).
Type SanitizeType(Type e)
A helper sanitizer/checker for the output of CalcType.
internal::Ops CalcOps() const
std::optional< std::vector< Opcode > > DecomposeScript(const CScript &script)
Decode a script into opcode/push pairs.
MaxInt< uint32_t > dsat
Number of keys in possibly executed OP_CHECKMULTISIG(VERIFY)s to dissatisfy.
A miniscript expression which does not begin with wrappers.
bool IsNonMalleable() const
Check whether this script can always be satisfied in a non-malleable way.
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.
OP_IF [X] OP_ELSE [Y] OP_ENDIF.
static const auto EMPTY
The empty stack.
[n] OP_CHECKSEQUENCEVERIFY
Node(const Ctx &ctx, Fragment nt, std::vector< NodeRef< Key >> sub, std::vector< unsigned char > arg, uint32_t val=0)
bool IsSaneSubexpression() const
Whether the apparent policy of this node matches its script semantics. Doesn't guarantee it is a safe...
constexpr friend SatInfo operator|(const SatInfo &a, const SatInfo &b) noexcept
Script set union.
Node(internal::NoDupCheck, MiniscriptContext script_ctx, Fragment nt, std::vector< Key > key, uint32_t val=0)
friend int Compare(const Node< Key > &node1, const Node< Key > &node2)
Compare two miniscript subtrees, using a non-recursive algorithm.
A data structure to help the calculation of stack size limits.
bool CheckOpsLimit() const
Check the ops limit of this script against the consensus limit.
MAYBE_AND_V will check if the next part of the script could be a valid miniscript sub-expression...
static constexpr unsigned int MAX_STANDARD_P2WSH_SCRIPT_SIZE
The maximum size in bytes of a standard witnessScript.
bool NeedsSignature() const
Check whether this script always needs a signature.
MiniscriptContext GetMsCtx() const
Return the script context for this node.
constexpr uint32_t P2WSH_TXOUT_BYTES
nValue + script len + OP_0 + pushdata 32.
static bool verify(const CScriptNum10 &bignum, const CScriptNum &scriptnum)
static constexpr unsigned int MAX_PUBKEYS_PER_MULTI_A
The limit of keys in OP_CHECKSIGADD-based scripts.
NON_ZERO wraps the top constructed node with j:
WitnessSize(MaxInt< uint32_t > in_sat, MaxInt< uint32_t > in_dsat)
OP_DUP OP_IF [X] OP_ENDIF.
constexpr Type operator &(Type x) const
Compute the type with the intersection of properties.
Class whose objects represent the maximum of a list of integers.
const bool valid
Whether a canonical satisfaction/dissatisfaction is possible at all.
COMMA expects the next element to be ',' and fails if not.
bool Const(const std::string &str, Span< const char > &sp)
Parse a constant.
#define CHECK(cond)
Unconditional failure on condition failure.
internal::WitnessSize CalcWitnessSize() const
static const auto ZERO
A stack consisting of a single zero-length element (interpreted as 0 by the script interpreter in num...
size_t ScriptSize() const
Return the size of the script for this expression (faster than ToScript().size()).
static constexpr SatInfo OP_CHECKSIG() noexcept
THRESH_E constructs a thresh node from the appropriate number of constructed children.
static constexpr size_t TAPROOT_CONTROL_MAX_SIZE
constexpr StackSize(SatInfo in_sat, SatInfo in_dsat) noexcept
Node(internal::NoDupCheck, MiniscriptContext script_ctx, Fragment nt, std::vector< NodeRef< Key >> sub, std::vector< Key > key, std::vector< unsigned char > arg, uint32_t val)
Node(const Ctx &ctx, Fragment nt, std::vector< Key > key, uint32_t val=0)
NodeRef< Key > Parse(Span< const char > in, const Ctx &ctx)
Parse a miniscript from its textual descriptor form.
std::unique_ptr< const Node< Key > > NodeRef
std::optional< std::string > ToString(const CTx &ctx) const
constexpr friend SatInfo operator+(const SatInfo &a, const SatInfo &b) noexcept
Script set concatenation.
MaxInt< uint32_t > sat
Number of keys in possibly executed OP_CHECKMULTISIG(VERIFY)s to satisfy.
constexpr C * begin() const noexcept
OP_SIZE OP_0NOTEQUAL OP_IF [X] OP_ENDIF.
const std::vector< Key > keys
The keys used by this expression (only for PK_K/PK_H/MULTI)
bool operator==(const Node< Key > &arg) const
Equality testing.
static constexpr SatInfo Empty() noexcept
The empty script.
static constexpr int32_t MAX_STANDARD_TX_WEIGHT
The maximum weight for transactions we're willing to relay/mine.
bool IsSatisfiable(F fn) const
Determine whether a Miniscript node is satisfiable.
friend MaxInt< I > operator|(const MaxInt< I > &a, const MaxInt< I > &b)
constexpr Type operator|(Type x) const
Compute the type with the union of properties.
Result TreeEval(State root_state, DownFn &&downfn, UpFn upfn) const
Like TreeEvalMaybe, but always produces a result.
std::optional< uint32_t > GetOps() const
Return the maximum number of ops needed to satisfy this script non-malleably.
bool CheckStackSize() const
Check the maximum stack size for this script against the policy limit.
Node(const Ctx &ctx, Fragment nt, std::vector< NodeRef< Key >> sub, uint32_t val=0)
constexpr uint32_t MAX_TAPSCRIPT_SAT_SIZE
Maximum possible stack size to spend a Taproot output (excluding the script itself).
constexpr C * data() const noexcept
Serialized script, used inside transaction inputs and outputs.
static const int MAX_OPS_PER_SCRIPT
Fragment
The different node types in miniscript.
bool IsBKW() const
Whether this node is of type B, K or W.
static constexpr SatInfo Hash() noexcept
A script consisting of a single hash opcode.
static constexpr SatInfo OP_DUP() noexcept
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)...
static constexpr unsigned int MAX_STANDARD_P2WSH_STACK_ITEMS
The maximum number of witness stack items in a standard P2WSH script.
static constexpr SatInfo OP_VERIFY() noexcept
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
std::vector< NodeRef< Key > > subs
Subexpressions (for WRAP_*/AND_*/OR_*/ANDOR/THRESH)
static constexpr SatInfo OP_IFDUP(bool nonzero) noexcept
NodeRef< Key > MakeNodeRef(Args &&... args)
Construct a miniscript node as a unique_ptr.
std::optional< uint32_t > GetStackSize() const
Return the maximum number of stack elements needed to satisfy this script non-malleably.
DUP_IF wraps the top constructed node with d:
const internal::StackSize ss
Cached stack size bounds.
bool IsValidTopLevel() const
Check whether this node is valid as a script on its own.
std::optional< uint32_t > GetExecStackSize() const
Return the maximum size of the stack during execution of this script.
OP_SIZE 32 OP_EQUALVERIFY OP_SHA256 [hash] OP_EQUAL.
void DuplicateKeyCheck(const Ctx &ctx) const
Update duplicate key information in this Node.
An expression of type W (a: or s: wrappers).
constexpr bool operator<(Type x) const
Comparison operator to enable use in sets/maps (total ordering incompatible with <<).
bool ValidSatisfactions() const
Whether successful non-malleable satisfactions are guaranteed to be valid.
A Span is an object that can refer to a contiguous sequence of objects.
uint256 Hash(const T &in1)
Compute the 256-bit hash of an object.
constexpr Type(uint32_t flags) noexcept
Internal constructor.
static constexpr SatInfo Push() noexcept
A script consisting of a single push opcode.
Type GetType() const
Return the expression type.
NodeRef< typename Ctx::Key > FromScript(const CScript &script, const Ctx &ctx)
OP_SIZE 32 OP_EQUALVERIFY OP_HASH256 [hash] OP_EQUAL.
[key_0] OP_CHECKSIG ([key_n] OP_CHECKSIGADD)* [k] OP_NUMEQUAL (only within Tapscript ctx) ...
static const std::vector< uint8_t > EMPTY
Node(internal::NoDupCheck, MiniscriptContext script_ctx, Fragment nt, std::vector< NodeRef< Key >> sub, uint32_t val=0)
Result TreeEval(UpFn upfn) const
Like TreeEval, but without downfn or State type.
constexpr uint32_t MaxScriptSize(MiniscriptContext ms_ctx)
The maximum size of a script depending on the context.
static const int MAX_STACK_SIZE
Node(internal::NoDupCheck, MiniscriptContext script_ctx, Fragment nt, std::vector< NodeRef< Key >> sub, std::vector< unsigned char > arg, uint32_t val=0)
CONSTEXPR_IF_NOT_DEBUG Span< C > last(std::size_t count) const noexcept
Node(internal::NoDupCheck, MiniscriptContext script_ctx, Fragment nt, std::vector< NodeRef< Key >> sub, std::vector< Key > key, uint32_t val=0)
constexpr unsigned int GetSizeOfCompactSize(uint64_t nSize)
Compact Size size < 253 – 1 byte size <= USHRT_MAX – 3 bytes (253 + 2 bytes) size <= UINT_MAX –...
If, inside an ENDIF context, we find an OP_ELSE, then we could be in either an or_i or an andor node...
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...
constexpr uint32_t TX_BODY_LEEWAY_WEIGHT
Data other than the witness in a transaction. Overhead + vin count + one vin + vout count + one vout ...
static constexpr SatInfo OP_EQUALVERIFY() noexcept
This type encapsulates the miniscript type system properties.
std::string ToString(const T &t)
Locale-independent version of std::to_string.
static const auto INVALID
A stack representing the lack of any (dis)satisfactions.
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...
static constexpr SatInfo If() noexcept
A script consisting of just OP_IF or OP_NOTIF.
const internal::Ops ops
Cached ops counts.
CScript ToScript(const Ctx &ctx) const
std::optional< int64_t > ParseScriptNumber(const Opcode &in)
Determine whether the passed pair (created by DecomposeScript) is pushing a number.
internal::StackSize CalcStackSize() const
constexpr uint32_t TX_OVERHEAD
version + nLockTime
bool CheckTimeLocksMix() const
Check whether there is no satisfaction path that contains both timelocks and heightlocks.
static constexpr SatInfo OP_EQUAL() noexcept