5#ifndef BITCOIN_SCRIPT_MINISCRIPT_H
6#define BITCOIN_SCRIPT_MINISCRIPT_H
157inline 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)
189using Opcode = std::pair<opcodetype, std::vector<unsigned char>>;
191template<
typename Key>
struct Node;
192template<
typename Key>
using NodeRef = std::unique_ptr<const Node<Key>>;
195template<
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}; }
503template<
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();
534 auto upfn = [](
const Node&
node, std::span<NodeRef<Key>> children) {
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>
604 std::optional<Result>
TreeEvalMaybe(State root_state, DownFn downfn, UpFn upfn)
const
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,
653 std::span<Result>{results}.last(
node.subs.size()))};
655 if (!result)
return {};
657 results.erase(results.end() -
node.subs.size(), results.end());
658 results.push_back(std::move(*result));
662 assert(results.size() >= 1);
664 return std::move(results[0]);
669 template<
typename Result,
typename UpFn>
672 struct DummyState {};
673 return TreeEvalMaybe<Result>(DummyState{},
674 [](DummyState,
const Node&, size_t) {
return DummyState{}; },
675 [&upfn](DummyState,
const Node&
node, std::span<Result>
subs) {
682 template<
typename Result,
typename State,
typename DownFn,
typename UpFn>
687 return std::move(*TreeEvalMaybe<Result>(std::move(root_state),
688 std::forward<DownFn>(downfn),
689 [&upfn](State&& state,
const Node&
node, std::span<Result>
subs) {
691 return std::optional<Result>(std::move(res));
698 template<
typename Result,
typename UpFn>
701 struct DummyState {};
702 return std::move(*TreeEvalMaybe<Result>(DummyState{},
703 [](DummyState,
const Node&, size_t) {
return DummyState{}; },
704 [&upfn](DummyState,
const Node&
node, std::span<Result>
subs) {
706 return std::optional<Result>(std::move(res));
714 std::vector<std::pair<const Node<Key>&,
const Node<Key>&>> queue;
715 queue.emplace_back(node1, node2);
716 while (!queue.empty()) {
717 const auto& [a, b] = queue.back();
719 if (std::tie(a.fragment, a.k, a.keys, a.data) < std::tie(b.fragment, b.k, b.keys, b.data))
return -1;
720 if (std::tie(b.fragment, b.k, b.keys, b.data) < std::tie(a.fragment, a.k, a.keys, a.data))
return 1;
721 if (a.subs.size() < b.subs.size())
return -1;
722 if (b.subs.size() < a.subs.size())
return 1;
723 size_t n = a.
subs.size();
724 for (
size_t i = 0; i < n; ++i) {
725 queue.emplace_back(*a.subs[n - 1 - i], *b.subs[n - 1 - i]);
733 using namespace internal;
736 std::vector<Type> sub_types;
738 for (
const auto& sub :
subs) sub_types.push_back(sub->GetType());
741 static constexpr auto NONE_MST{
""_mst};
742 Type x =
subs.size() > 0 ?
subs[0]->GetType() : NONE_MST;
743 Type y =
subs.size() > 1 ?
subs[1]->GetType() : NONE_MST;
744 Type z =
subs.size() > 2 ?
subs[2]->GetType() : NONE_MST;
750 template<
typename Ctx>
769 switch (
node.fragment) {
783 if (
node.subs[0]->GetType() <<
"x"_mst) {
786 return std::move(
subs[0]);
803 for (
const auto& key :
node.keys) {
811 for (
auto it =
node.keys.begin() + 1; it !=
node.keys.end(); ++it) {
818 for (
size_t i = 1; i <
subs.size(); ++i) {
826 return TreeEval<CScript>(
false, downfn, upfn);
829 template<
typename CTx>
830 std::optional<std::string>
ToString(
const CTx& ctx)
const {
834 auto downfn = [](bool,
const Node&
node, size_t) {
846 auto upfn = [&ctx, is_tapscript](
bool wrapped,
const Node&
node, std::span<std::string>
subs) -> std::optional<std::string> {
847 std::string
ret = wrapped ?
":" :
"";
849 switch (
node.fragment) {
855 auto key_str = ctx.ToString(
node.subs[0]->keys[0]);
856 if (!key_str)
return {};
857 return std::move(
ret) +
"pk(" + std::move(*key_str) +
")";
861 auto key_str = ctx.ToString(
node.subs[0]->keys[0]);
862 if (!key_str)
return {};
863 return std::move(
ret) +
"pkh(" + std::move(*key_str) +
")";
865 return "c" + std::move(
subs[0]);
880 switch (
node.fragment) {
882 auto key_str = ctx.ToString(
node.keys[0]);
883 if (!key_str)
return {};
884 return std::move(
ret) +
"pk_k(" + std::move(*key_str) +
")";
887 auto key_str = ctx.ToString(
node.keys[0]);
888 if (!key_str)
return {};
889 return std::move(
ret) +
"pk_h(" + std::move(*key_str) +
")";
908 return std::move(
ret) +
"andor(" + std::move(
subs[0]) +
"," + std::move(
subs[1]) +
"," + std::move(
subs[2]) +
")";
912 for (
const auto& key :
node.keys) {
913 auto key_str = ctx.ToString(key);
914 if (!key_str)
return {};
915 str +=
"," + std::move(*key_str);
917 return std::move(str) +
")";
922 for (
const auto& key :
node.keys) {
923 auto key_str = ctx.ToString(key);
924 if (!key_str)
return {};
925 str +=
"," + std::move(*key_str);
927 return std::move(str) +
")";
931 for (
auto& sub :
subs) {
932 str +=
"," + std::move(sub);
934 return std::move(str) +
")";
941 return TreeEvalMaybe<std::string>(
false, downfn, upfn);
959 const auto count{1 +
subs[0]->ops.count +
subs[1]->ops.count};
960 const auto sat{
subs[0]->ops.sat +
subs[1]->ops.sat};
961 const auto dsat{
subs[0]->ops.dsat +
subs[1]->ops.dsat};
962 return {
count, sat, dsat};
965 const auto count{1 +
subs[0]->ops.count +
subs[1]->ops.count};
967 const auto dsat{
subs[0]->ops.dsat +
subs[1]->ops.dsat};
968 return {
count, sat, dsat};
971 const auto count{3 +
subs[0]->ops.count +
subs[1]->ops.count};
972 const auto sat{
subs[0]->ops.sat | (
subs[1]->ops.sat +
subs[0]->ops.dsat)};
973 const auto dsat{
subs[0]->ops.dsat +
subs[1]->ops.dsat};
974 return {
count, sat, dsat};
977 const auto count{2 +
subs[0]->ops.count +
subs[1]->ops.count};
978 const auto sat{
subs[0]->ops.sat | (
subs[1]->ops.sat +
subs[0]->ops.dsat)};
979 return {
count, sat, {}};
982 const auto count{3 +
subs[0]->ops.count +
subs[1]->ops.count};
983 const auto sat{
subs[0]->ops.sat |
subs[1]->ops.sat};
984 const auto dsat{
subs[0]->ops.dsat |
subs[1]->ops.dsat};
985 return {
count, sat, dsat};
988 const auto count{3 +
subs[0]->ops.count +
subs[1]->ops.count +
subs[2]->ops.count};
990 const auto dsat{
subs[0]->ops.dsat +
subs[2]->ops.dsat};
991 return {
count, sat, dsat};
1005 for (
const auto& sub :
subs) {
1006 count += sub->ops.count + 1;
1007 auto next_sats =
Vector(sats[0] + sub->ops.dsat);
1008 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub->ops.dsat) | (sats[j - 1] + sub->ops.sat));
1009 next_sats.push_back(sats[sats.size() - 1] + sub->ops.sat);
1010 sats = std::move(next_sats);
1013 return {
count, sats[
k], sats[0]};
1020 using namespace internal;
1036 const auto& x{subs[0]->ss};
1037 const auto& y{subs[1]->ss};
1038 const auto& z{subs[2]->ss};
1040 (x.sat + SatInfo::If() + y.sat) | (x.dsat + SatInfo::If() + z.sat),
1041 x.dsat + SatInfo::If() + z.dsat
1045 const auto& x{subs[0]->ss};
1046 const auto& y{subs[1]->ss};
1047 return {x.sat + y.sat, {}};
1050 const auto& x{subs[0]->ss};
1051 const auto& y{subs[1]->ss};
1052 return {x.sat + y.sat + SatInfo::BinaryOp(), x.dsat + y.dsat + SatInfo::BinaryOp()};
1055 const auto& x{subs[0]->ss};
1056 const auto& y{subs[1]->ss};
1058 ((x.sat + y.dsat) | (x.dsat + y.sat)) + SatInfo::BinaryOp(),
1059 x.dsat + y.dsat + SatInfo::BinaryOp()
1063 const auto& x{subs[0]->ss};
1064 const auto& y{subs[1]->ss};
1065 return {(x.sat + SatInfo::If()) | (x.dsat + SatInfo::If() + y.sat), {}};
1068 const auto& x{subs[0]->ss};
1069 const auto& y{subs[1]->ss};
1076 const auto& x{subs[0]->ss};
1077 const auto& y{subs[1]->ss};
1078 return {SatInfo::If() + (x.sat | y.sat), SatInfo::If() + (x.dsat | y.dsat)};
1107 auto sats =
Vector(SatInfo::Empty());
1108 for (
size_t i = 0; i < subs.size(); ++i) {
1111 auto add = i ? SatInfo::BinaryOp() : SatInfo::Empty();
1113 auto next_sats =
Vector(sats[0] + subs[i]->ss.dsat + add);
1115 for (
size_t j = 1; j < sats.size(); ++j) {
1116 next_sats.push_back(((sats[j] + subs[i]->ss.dsat) | (sats[j - 1] + subs[i]->ss.sat)) + add);
1119 next_sats.push_back(sats[sats.size() - 1] + subs[i]->ss.sat + add);
1121 sats = std::move(next_sats);
1136 const uint32_t pubkey_size =
IsTapscript(m_script_ctx) ? 1 + 32 : 1 + 33;
1149 const auto sat{(subs[0]->ws.sat + subs[1]->ws.sat) | (subs[0]->ws.dsat + subs[2]->ws.sat)};
1150 const auto dsat{subs[0]->ws.dsat + subs[2]->ws.dsat};
1154 case Fragment::AND_B:
return {subs[0]->ws.sat + subs[1]->ws.sat, subs[0]->ws.dsat + subs[1]->ws.dsat};
1156 const auto sat{(subs[0]->ws.dsat + subs[1]->ws.sat) | (subs[0]->ws.sat + subs[1]->ws.dsat)};
1157 const auto dsat{subs[0]->ws.dsat + subs[1]->ws.dsat};
1160 case Fragment::OR_C:
return {subs[0]->ws.sat | (subs[0]->ws.dsat + subs[1]->ws.sat), {}};
1161 case Fragment::OR_D:
return {subs[0]->ws.sat | (subs[0]->ws.dsat + subs[1]->ws.sat), subs[0]->ws.dsat + subs[1]->ws.dsat};
1162 case Fragment::OR_I:
return {(subs[0]->ws.sat + 1 + 1) | (subs[1]->ws.sat + 1), (subs[0]->ws.dsat + 1 + 1) | (subs[1]->ws.dsat + 1)};
1174 for (
const auto& sub : subs) {
1175 auto next_sats =
Vector(sats[0] + sub->ws.dsat);
1176 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub->ws.dsat) | (sats[j - 1] + sub->ws.sat));
1177 next_sats.push_back(sats[sats.size() - 1] + sub->ws.sat);
1178 sats = std::move(next_sats);
1181 return {sats[
k], sats[0]};
1187 template<
typename Ctx>
1189 using namespace internal;
1193 auto helper = [&ctx](
const Node&
node, std::span<InputResult> subres) -> InputResult {
1194 switch (
node.fragment) {
1196 std::vector<unsigned char> sig;
1198 return {
ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
1201 std::vector<unsigned char> key = ctx.ToPKBytes(
node.keys[0]), sig;
1203 return {
ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
1209 for (
size_t i = 0; i <
node.keys.size(); ++i) {
1212 std::vector<unsigned char> sig;
1215 auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1219 std::vector<InputStack> next_sats;
1220 next_sats.push_back(sats[0] +
ZERO);
1221 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] +
ZERO) | (std::move(sats[j - 1]) + sat));
1222 next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1224 sats = std::move(next_sats);
1228 auto& nsat{sats[0]};
1231 return {std::move(nsat), std::move(sats[
node.k])};
1238 for (
size_t i = 0; i <
node.keys.size(); ++i) {
1239 std::vector<unsigned char> sig;
1242 auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1246 std::vector<InputStack> next_sats;
1247 next_sats.push_back(sats[0]);
1248 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
1249 next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1251 sats = std::move(next_sats);
1254 InputStack nsat =
ZERO;
1255 for (
size_t i = 0; i <
node.k; ++i) nsat = std::move(nsat) +
ZERO;
1257 return {std::move(nsat), std::move(sats[
node.k])};
1264 for (
size_t i = 0; i < subres.size(); ++i) {
1266 auto& res = subres[subres.size() - i - 1];
1270 std::vector<InputStack> next_sats;
1271 next_sats.push_back(sats[0] + res.nsat);
1272 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + res.nsat) | (std::move(sats[j - 1]) + res.sat));
1273 next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
1275 sats = std::move(next_sats);
1279 InputStack nsat = INVALID;
1280 for (
size_t i = 0; i < sats.size(); ++i) {
1287 if (i != 0 && i !=
node.k) sats[i].SetMalleable().SetNonCanon();
1289 if (i !=
node.k) nsat = std::move(nsat) | std::move(sats[i]);
1292 return {std::move(nsat), std::move(sats[
node.k])};
1295 return {INVALID, ctx.CheckOlder(
node.k) ?
EMPTY : INVALID};
1298 return {INVALID, ctx.CheckAfter(
node.k) ?
EMPTY : INVALID};
1301 std::vector<unsigned char> preimage;
1303 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1306 std::vector<unsigned char> preimage;
1308 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1311 std::vector<unsigned char> preimage;
1313 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1316 std::vector<unsigned char> preimage;
1318 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1321 auto& x = subres[0], &y = subres[1];
1328 return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
1331 auto& x = subres[0], &y = subres[1];
1337 return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
1340 auto& x = subres[0], &z = subres[1];
1342 return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
1345 auto& x = subres[0], &z = subres[1];
1346 return {INVALID, std::move(x.sat) | (z.sat + x.nsat)};
1349 auto& x = subres[0], &z = subres[1];
1350 return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
1353 auto& x = subres[0], &z = subres[1];
1354 return {(x.nsat + ONE) | (z.nsat +
ZERO), (x.sat + ONE) | (z.sat +
ZERO)};
1357 auto& x = subres[0], &y = subres[1], &z = subres[2];
1358 return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
1364 return std::move(subres[0]);
1366 auto &x = subres[0];
1367 return {
ZERO, x.sat + ONE};
1370 auto &x = subres[0];
1376 return {InputStack(
ZERO).SetMalleable(x.nsat.available !=
Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
1379 auto &x = subres[0];
1380 return {INVALID, std::move(x.sat)};
1386 return {INVALID, INVALID};
1389 auto tester = [&helper](
const Node&
node, std::span<InputResult> subres) -> InputResult {
1390 auto ret = helper(
node, subres);
1432 return TreeEval<InputResult>(tester);
1447 Comp(
const Ctx& ctx) : ctx_ptr(&ctx) {}
1448 bool operator()(
const Key& a,
const Key& b)
const {
return ctx_ptr->KeyCompare(a, b); }
1454 using keyset = std::set<Key, Comp>;
1455 using state = std::optional<keyset>;
1457 auto upfn = [&ctx](
const Node&
node, std::span<state> subs) -> state {
1459 if (
node.has_duplicate_keys.has_value() && *
node.has_duplicate_keys)
return {};
1462 for (
auto& sub : subs) {
1463 if (!sub.has_value()) {
1464 node.has_duplicate_keys =
true;
1471 size_t keys_count =
node.keys.size();
1472 keyset key_set{
node.keys.begin(),
node.keys.end(), Comp(ctx)};
1473 if (key_set.size() != keys_count) {
1475 node.has_duplicate_keys =
true;
1480 for (
auto& sub : subs) {
1481 keys_count += sub->size();
1484 if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1485 key_set.merge(*sub);
1486 if (key_set.size() != keys_count) {
1487 node.has_duplicate_keys =
true;
1492 node.has_duplicate_keys =
false;
1496 TreeEval<state>(upfn);
1504 if (!ops.sat.valid)
return {};
1505 return ops.count + ops.sat.value;
1520 return !((GetType() &
"BKW"_mst) ==
""_mst);
1525 if (!ss.sat.valid)
return {};
1526 return ss.sat.netdiff +
static_cast<int32_t
>(IsBKW());
1531 if (!ss.sat.valid)
return {};
1532 return ss.sat.exec +
static_cast<int32_t
>(IsBKW());
1540 if (
const auto exec_ss = GetExecStackSize())
return exec_ss <=
MAX_STACK_SIZE;
1553 if (!ws.sat.valid)
return {};
1554 return ws.sat.value;
1565 return TreeEval<const Node*>([](
const Node&
node, std::span<const Node*> subs) ->
const Node* {
1566 for (
auto& sub: subs)
if (sub)
return sub;
1567 if (!
node.IsSaneSubexpression())
return &
node;
1574 template<
typename F>
1578 return TreeEval<int>([&fn](
const Node&
node, std::span<int> subs) ->
bool {
1579 switch (
node.fragment) {
1580 case Fragment::JUST_0:
1582 case Fragment::JUST_1:
1584 case Fragment::PK_K:
1585 case Fragment::PK_H:
1586 case Fragment::MULTI:
1587 case Fragment::MULTI_A:
1588 case Fragment::AFTER:
1589 case Fragment::OLDER:
1590 case Fragment::HASH256:
1591 case Fragment::HASH160:
1592 case Fragment::SHA256:
1593 case Fragment::RIPEMD160:
1594 return bool{fn(node)};
1596 return (subs[0] && subs[1]) || subs[2];
1599 return subs[0] && subs[1];
1604 return subs[0] || subs[1];
1606 return static_cast<uint32_t
>(
std::count(subs.begin(), subs.end(),
true)) >=
node.k;
1608 assert(subs.size() >= 1);
1617 if (GetType() ==
""_mst)
return false;
1640 bool IsSaneSubexpression()
const {
return ValidSatisfactions() && IsNonMalleable() && CheckTimeLocksMix() && CheckDuplicateKey(); }
1643 bool IsSane()
const {
return IsValidTopLevel() && IsSaneSubexpression() && NeedsSignature(); }
1649 template<
typename Ctx>
1650 Availability Satisfy(
const Ctx& ctx, std::vector<std::vector<unsigned char>>& stack,
bool nonmalleable =
true)
const {
1651 auto ret = ProduceInput(ctx);
1652 if (nonmalleable && (
ret.sat.malleable || !
ret.sat.has_sig))
return Availability::NO;
1653 stack = std::move(
ret.sat.stack);
1654 return ret.sat.available;
1662 : fragment(nt),
k(val),
data(
std::move(arg)), subs(
std::move(sub)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1664 : fragment(nt),
k(val),
data(
std::move(arg)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1666 : fragment(nt),
k(val), keys(
std::move(key)), m_script_ctx{script_ctx}, subs(
std::move(sub)), ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1668 : fragment(nt),
k(val), keys(
std::move(key)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1670 : fragment(nt),
k(val), subs(
std::move(sub)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1672 : fragment(nt),
k(val), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1675 template <
typename Ctx>
Node(
const Ctx& ctx,
Fragment nt, std::vector<
NodeRef<Key>> sub, std::vector<unsigned char> arg, uint32_t val = 0)
1676 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(sub),
std::move(arg), val) { DuplicateKeyCheck(ctx); }
1677 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(arg), val) { DuplicateKeyCheck(ctx);}
1680 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(sub),
std::move(key), val) { DuplicateKeyCheck(ctx); }
1681 template <
typename Ctx>
Node(
const Ctx& ctx,
Fragment nt, std::vector<Key> key, uint32_t val = 0)
1682 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(key), val) { DuplicateKeyCheck(ctx); }
1684 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(sub), val) { DuplicateKeyCheck(ctx); }
1685 template <
typename Ctx>
Node(
const Ctx& ctx,
Fragment nt, uint32_t val = 0)
1686 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt, val) { DuplicateKeyCheck(ctx); }
1752template<
typename Key,
typename Ctx>
1753std::optional<std::pair<Key, int>>
ParseKeyEnd(std::span<const char> in,
const Ctx& ctx)
1756 if (key_size < 1)
return {};
1757 auto key = ctx.FromString(in.begin(), in.begin() + key_size);
1758 if (!key)
return {};
1759 return {{std::move(*key), key_size}};
1763template<
typename Ctx>
1764std::optional<std::pair<std::vector<unsigned char>,
int>>
ParseHexStrEnd(std::span<const char> in,
const size_t expected_size,
1768 if (hash_size < 1)
return {};
1769 std::string val = std::string(in.begin(), in.begin() + hash_size);
1770 if (!
IsHex(val))
return {};
1772 if (hash.size() != expected_size)
return {};
1773 return {{std::move(hash), hash_size}};
1777template<
typename Key>
1781 constructed.pop_back();
1783 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, script_ctx, nt,
Vector(std::move(child), std::move(constructed.back())));
1785 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, script_ctx, nt,
Vector(std::move(constructed.back()), std::move(child)));
1794template<
typename Key,
typename Ctx>
1809 size_t script_size{1};
1813 std::vector<std::tuple<ParseContext, int64_t, int64_t>> to_parse;
1814 std::vector<NodeRef<Key>> constructed;
1816 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
1819 const auto parse_multi_exp = [&](std::span<const char>& in,
const bool is_multi_a) ->
bool {
1821 const auto required_ctx{is_multi_a ? MiniscriptContext::TAPSCRIPT : MiniscriptContext::P2WSH};
1822 if (ctx.MsContext() != required_ctx)
return false;
1825 if (next_comma < 1)
return false;
1826 const auto k_to_integral{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
1827 if (!k_to_integral.has_value())
return false;
1828 const int64_t
k{k_to_integral.value()};
1829 in = in.subspan(next_comma + 1);
1831 std::vector<Key> keys;
1832 while (next_comma != -1) {
1834 int key_length = (next_comma == -1) ?
FindNextChar(in,
')') : next_comma;
1835 if (key_length < 1)
return false;
1836 auto key = ctx.FromString(in.begin(), in.begin() + key_length);
1837 if (!key)
return false;
1838 keys.push_back(std::move(*key));
1839 in = in.subspan(key_length + 1);
1841 if (keys.size() < 1 || keys.size() > max_keys)
return false;
1842 if (k < 1 || k > (int64_t)keys.size())
return false;
1846 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys),
k));
1848 script_size += 2 + (keys.size() > 16) + (
k > 16) + 34 * keys.size();
1849 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys),
k));
1854 while (!to_parse.empty()) {
1855 if (script_size > max_size)
return {};
1858 auto [cur_context, n,
k] = to_parse.back();
1859 to_parse.pop_back();
1861 switch (cur_context) {
1862 case ParseContext::WRAPPED_EXPR: {
1863 std::optional<size_t> colon_index{};
1864 for (
size_t i = 1; i < in.size(); ++i) {
1869 if (in[i] <
'a' || in[i] >
'z')
break;
1872 bool last_was_v{
false};
1873 for (
size_t j = 0; colon_index && j < *colon_index; ++j) {
1874 if (script_size > max_size)
return {};
1877 to_parse.emplace_back(ParseContext::ALT, -1, -1);
1878 }
else if (in[j] ==
's') {
1880 to_parse.emplace_back(ParseContext::SWAP, -1, -1);
1881 }
else if (in[j] ==
'c') {
1884 }
else if (in[j] ==
'd') {
1886 to_parse.emplace_back(ParseContext::DUP_IF, -1, -1);
1887 }
else if (in[j] ==
'j') {
1889 to_parse.emplace_back(ParseContext::NON_ZERO, -1, -1);
1890 }
else if (in[j] ==
'n') {
1892 to_parse.emplace_back(ParseContext::ZERO_NOTEQUAL, -1, -1);
1893 }
else if (in[j] ==
'v') {
1896 if (last_was_v)
return {};
1897 to_parse.emplace_back(ParseContext::VERIFY, -1, -1);
1898 }
else if (in[j] ==
'u') {
1900 to_parse.emplace_back(ParseContext::WRAP_U, -1, -1);
1901 }
else if (in[j] ==
't') {
1903 to_parse.emplace_back(ParseContext::WRAP_T, -1, -1);
1904 }
else if (in[j] ==
'l') {
1907 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0));
1908 to_parse.emplace_back(ParseContext::OR_I, -1, -1);
1912 last_was_v = (in[j] ==
'v');
1914 to_parse.emplace_back(ParseContext::EXPR, -1, -1);
1915 if (colon_index) in = in.subspan(*colon_index + 1);
1918 case ParseContext::EXPR: {
1919 if (
Const(
"0", in)) {
1920 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0));
1921 }
else if (
Const(
"1", in)) {
1922 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1));
1923 }
else if (
Const(
"pk(", in)) {
1924 auto res = ParseKeyEnd<Key, Ctx>(in, ctx);
1925 if (!res)
return {};
1926 auto& [key, key_size] = *res;
1928 in = in.subspan(key_size + 1);
1929 script_size +=
IsTapscript(ctx.MsContext()) ? 33 : 34;
1930 }
else if (
Const(
"pkh(", in)) {
1931 auto res = ParseKeyEnd<Key>(in, ctx);
1932 if (!res)
return {};
1933 auto& [key, key_size] = *res;
1935 in = in.subspan(key_size + 1);
1937 }
else if (
Const(
"pk_k(", in)) {
1938 auto res = ParseKeyEnd<Key>(in, ctx);
1939 if (!res)
return {};
1940 auto& [key, key_size] = *res;
1942 in = in.subspan(key_size + 1);
1943 script_size +=
IsTapscript(ctx.MsContext()) ? 32 : 33;
1944 }
else if (
Const(
"pk_h(", in)) {
1945 auto res = ParseKeyEnd<Key>(in, ctx);
1946 if (!res)
return {};
1947 auto& [key, key_size] = *res;
1949 in = in.subspan(key_size + 1);
1951 }
else if (
Const(
"sha256(", in)) {
1953 if (!res)
return {};
1954 auto& [hash, hash_size] = *res;
1955 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, std::move(hash)));
1956 in = in.subspan(hash_size + 1);
1958 }
else if (
Const(
"ripemd160(", in)) {
1960 if (!res)
return {};
1961 auto& [hash, hash_size] = *res;
1963 in = in.subspan(hash_size + 1);
1965 }
else if (
Const(
"hash256(", in)) {
1967 if (!res)
return {};
1968 auto& [hash, hash_size] = *res;
1969 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, std::move(hash)));
1970 in = in.subspan(hash_size + 1);
1972 }
else if (
Const(
"hash160(", in)) {
1974 if (!res)
return {};
1975 auto& [hash, hash_size] = *res;
1976 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, std::move(hash)));
1977 in = in.subspan(hash_size + 1);
1979 }
else if (
Const(
"after(", in)) {
1981 if (arg_size < 1)
return {};
1982 const auto num{ToIntegral<int64_t>(std::string_view(in.data(), arg_size))};
1983 if (!num.has_value() || *num < 1 || *num >= 0x80000000L)
return {};
1984 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num));
1985 in = in.subspan(arg_size + 1);
1986 script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
1987 }
else if (
Const(
"older(", in)) {
1989 if (arg_size < 1)
return {};
1990 const auto num{ToIntegral<int64_t>(std::string_view(in.data(), arg_size))};
1991 if (!num.has_value() || *num < 1 || *num >= 0x80000000L)
return {};
1992 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num));
1993 in = in.subspan(arg_size + 1);
1994 script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
1995 }
else if (
Const(
"multi(", in)) {
1996 if (!parse_multi_exp(in,
false))
return {};
1997 }
else if (
Const(
"multi_a(", in)) {
1998 if (!parse_multi_exp(in,
true))
return {};
1999 }
else if (
Const(
"thresh(", in)) {
2001 if (next_comma < 1)
return {};
2002 const auto k{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
2003 if (!
k.has_value() || *
k < 1)
return {};
2004 in = in.subspan(next_comma + 1);
2006 to_parse.emplace_back(ParseContext::THRESH, 1, *
k);
2007 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2008 script_size += 2 + (*
k > 16) + (*
k > 0x7f) + (*
k > 0x7fff) + (*
k > 0x7fffff);
2009 }
else if (
Const(
"andor(", in)) {
2010 to_parse.emplace_back(ParseContext::ANDOR, -1, -1);
2011 to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -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);
2015 to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2016 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2019 if (
Const(
"and_n(", in)) {
2020 to_parse.emplace_back(ParseContext::AND_N, -1, -1);
2022 }
else if (
Const(
"and_b(", in)) {
2023 to_parse.emplace_back(ParseContext::AND_B, -1, -1);
2025 }
else if (
Const(
"and_v(", in)) {
2026 to_parse.emplace_back(ParseContext::AND_V, -1, -1);
2028 }
else if (
Const(
"or_b(", in)) {
2029 to_parse.emplace_back(ParseContext::OR_B, -1, -1);
2031 }
else if (
Const(
"or_c(", in)) {
2032 to_parse.emplace_back(ParseContext::OR_C, -1, -1);
2034 }
else if (
Const(
"or_d(", in)) {
2035 to_parse.emplace_back(ParseContext::OR_D, -1, -1);
2037 }
else if (
Const(
"or_i(", in)) {
2038 to_parse.emplace_back(ParseContext::OR_I, -1, -1);
2043 to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
2044 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2045 to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2046 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2050 case ParseContext::ALT: {
2051 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A,
Vector(std::move(constructed.back())));
2054 case ParseContext::SWAP: {
2055 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S,
Vector(std::move(constructed.back())));
2059 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C,
Vector(std::move(constructed.back())));
2062 case ParseContext::DUP_IF: {
2063 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D,
Vector(std::move(constructed.back())));
2066 case ParseContext::NON_ZERO: {
2067 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J,
Vector(std::move(constructed.back())));
2070 case ParseContext::ZERO_NOTEQUAL: {
2071 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N,
Vector(std::move(constructed.back())));
2074 case ParseContext::VERIFY: {
2075 script_size += (constructed.back()->GetType() <<
"x"_mst);
2076 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V,
Vector(std::move(constructed.back())));
2079 case ParseContext::WRAP_U: {
2083 case ParseContext::WRAP_T: {
2087 case ParseContext::AND_B: {
2088 BuildBack(ctx.MsContext(), Fragment::AND_B, constructed);
2091 case ParseContext::AND_N: {
2092 auto mid = std::move(constructed.back());
2093 constructed.pop_back();
2094 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR,
Vector(std::move(constructed.back()), std::move(mid), MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0)));
2097 case ParseContext::AND_V: {
2098 BuildBack(ctx.MsContext(), Fragment::AND_V, constructed);
2101 case ParseContext::OR_B: {
2102 BuildBack(ctx.MsContext(), Fragment::OR_B, constructed);
2105 case ParseContext::OR_C: {
2106 BuildBack(ctx.MsContext(), Fragment::OR_C, constructed);
2109 case ParseContext::OR_D: {
2110 BuildBack(ctx.MsContext(), Fragment::OR_D, constructed);
2113 case ParseContext::OR_I: {
2114 BuildBack(ctx.MsContext(), Fragment::OR_I, constructed);
2117 case ParseContext::ANDOR: {
2118 auto right = std::move(constructed.back());
2119 constructed.pop_back();
2120 auto mid = std::move(constructed.back());
2121 constructed.pop_back();
2122 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR,
Vector(std::move(constructed.back()), std::move(mid), std::move(right)));
2125 case ParseContext::THRESH: {
2126 if (in.size() < 1)
return {};
2129 to_parse.emplace_back(ParseContext::THRESH, n+1,
k);
2130 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2132 }
else if (in[0] ==
')') {
2133 if (
k > n)
return {};
2136 std::vector<NodeRef<Key>> subs;
2137 for (
int i = 0; i < n; ++i) {
2138 subs.push_back(std::move(constructed.back()));
2139 constructed.pop_back();
2141 std::reverse(subs.begin(), subs.end());
2142 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs),
k));
2148 case ParseContext::COMMA: {
2149 if (in.size() < 1 || in[0] !=
',')
return {};
2153 case ParseContext::CLOSE_BRACKET: {
2154 if (in.size() < 1 || in[0] !=
')')
return {};
2162 assert(constructed.size() >= 1);
2164 assert(constructed[0]->ScriptSize() == script_size);
2165 if (in.size() > 0)
return {};
2167 tl_node->DuplicateKeyCheck(ctx);
2253template<
typename Key,
typename Ctx,
typename I>
2257 std::vector<std::tuple<DecodeContext, int64_t, int64_t>> to_parse;
2258 std::vector<NodeRef<Key>> constructed;
2262 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2264 while (!to_parse.empty()) {
2266 if (!constructed.empty() && !constructed.back()->IsValid())
return {};
2269 auto [cur_context, n,
k] = to_parse.back();
2270 to_parse.pop_back();
2272 switch(cur_context) {
2273 case DecodeContext::SINGLE_BKV_EXPR: {
2274 if (in >= last)
return {};
2277 if (in[0].first ==
OP_1) {
2279 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1));
2282 if (in[0].first ==
OP_0) {
2284 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0));
2288 if (in[0].second.size() == 33 || in[0].second.size() == 32) {
2289 auto key = ctx.FromPKBytes(in[0].second.begin(), in[0].second.end());
2290 if (!key)
return {};
2296 auto key = ctx.FromPKHBytes(in[2].second.begin(), in[2].second.end());
2297 if (!key)
return {};
2303 std::optional<int64_t> num;
2306 if (*num < 1 || *num > 0x7FFFFFFFL)
return {};
2307 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num));
2312 if (num < 1 || num > 0x7FFFFFFFL)
return {};
2313 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num));
2318 if (in[2].first ==
OP_SHA256 && in[1].second.size() == 32) {
2319 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, in[1].second));
2322 }
else if (in[2].first ==
OP_RIPEMD160 && in[1].second.size() == 20) {
2326 }
else if (in[2].first ==
OP_HASH256 && in[1].second.size() == 32) {
2327 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, in[1].second));
2330 }
else if (in[2].first ==
OP_HASH160 && in[1].second.size() == 20) {
2331 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, in[1].second));
2339 std::vector<Key> keys;
2341 if (!n || last - in < 3 + *n)
return {};
2342 if (*n < 1 || *n > 20)
return {};
2343 for (
int i = 0; i < *n; ++i) {
2344 if (in[2 + i].second.size() != 33)
return {};
2345 auto key = ctx.FromPKBytes(in[2 + i].second.begin(), in[2 + i].second.end());
2346 if (!key)
return {};
2347 keys.push_back(std::move(*key));
2350 if (!
k || *k < 1 || *k > *n)
return {};
2352 std::reverse(keys.begin(), keys.end());
2353 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), *
k));
2357 if (last - in >= 4 && in[0].first ==
OP_NUMEQUAL) {
2363 if (last - in < 2 + *
k * 2)
return {};
2364 std::vector<Key> keys;
2367 for (
int pos = 2;; pos += 2) {
2368 if (last - in < pos + 2)
return {};
2371 if (in[pos + 1].second.size() != 32)
return {};
2372 auto key = ctx.FromPKBytes(in[pos + 1].second.begin(), in[pos + 1].second.end());
2373 if (!key)
return {};
2374 keys.push_back(std::move(*key));
2380 if (keys.size() < (
size_t)*
k)
return {};
2381 in += 2 + keys.size() * 2;
2382 std::reverse(keys.begin(), keys.end());
2383 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), *
k));
2393 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2399 to_parse.emplace_back(DecodeContext::VERIFY, -1, -1);
2400 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2406 to_parse.emplace_back(DecodeContext::ZERO_NOTEQUAL, -1, -1);
2407 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2412 if (*num < 1)
return {};
2414 to_parse.emplace_back(DecodeContext::THRESH_W, 0, *num);
2420 to_parse.emplace_back(DecodeContext::ENDIF, -1, -1);
2421 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2432 to_parse.emplace_back(DecodeContext::AND_B, -1, -1);
2433 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2434 to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2440 to_parse.emplace_back(DecodeContext::OR_B, -1, -1);
2441 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2442 to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2448 case DecodeContext::BKV_EXPR: {
2449 to_parse.emplace_back(DecodeContext::MAYBE_AND_V, -1, -1);
2450 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2453 case DecodeContext::W_EXPR: {
2455 if (in >= last)
return {};
2458 to_parse.emplace_back(DecodeContext::ALT, -1, -1);
2460 to_parse.emplace_back(DecodeContext::SWAP, -1, -1);
2462 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2465 case DecodeContext::MAYBE_AND_V: {
2469 to_parse.emplace_back(DecodeContext::AND_V, -1, -1);
2471 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2475 case DecodeContext::SWAP: {
2476 if (in >= last || in[0].first !=
OP_SWAP || constructed.empty())
return {};
2478 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S,
Vector(std::move(constructed.back())));
2481 case DecodeContext::ALT: {
2482 if (in >= last || in[0].first !=
OP_TOALTSTACK || constructed.empty())
return {};
2484 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A,
Vector(std::move(constructed.back())));
2488 if (constructed.empty())
return {};
2489 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C,
Vector(std::move(constructed.back())));
2492 case DecodeContext::DUP_IF: {
2493 if (constructed.empty())
return {};
2494 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D,
Vector(std::move(constructed.back())));
2497 case DecodeContext::VERIFY: {
2498 if (constructed.empty())
return {};
2499 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V,
Vector(std::move(constructed.back())));
2502 case DecodeContext::NON_ZERO: {
2503 if (constructed.empty())
return {};
2504 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J,
Vector(std::move(constructed.back())));
2507 case DecodeContext::ZERO_NOTEQUAL: {
2508 if (constructed.empty())
return {};
2509 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N,
Vector(std::move(constructed.back())));
2512 case DecodeContext::AND_V: {
2513 if (constructed.size() < 2)
return {};
2514 BuildBack(ctx.MsContext(), Fragment::AND_V, constructed,
true);
2517 case DecodeContext::AND_B: {
2518 if (constructed.size() < 2)
return {};
2519 BuildBack(ctx.MsContext(), Fragment::AND_B, constructed,
true);
2522 case DecodeContext::OR_B: {
2523 if (constructed.size() < 2)
return {};
2524 BuildBack(ctx.MsContext(), Fragment::OR_B, constructed,
true);
2527 case DecodeContext::OR_C: {
2528 if (constructed.size() < 2)
return {};
2529 BuildBack(ctx.MsContext(), Fragment::OR_C, constructed,
true);
2532 case DecodeContext::OR_D: {
2533 if (constructed.size() < 2)
return {};
2534 BuildBack(ctx.MsContext(), Fragment::OR_D, constructed,
true);
2537 case DecodeContext::ANDOR: {
2538 if (constructed.size() < 3)
return {};
2540 constructed.pop_back();
2542 constructed.pop_back();
2544 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR,
Vector(std::move(left), std::move(mid), std::move(right)));
2547 case DecodeContext::THRESH_W: {
2548 if (in >= last)
return {};
2549 if (in[0].first ==
OP_ADD) {
2551 to_parse.emplace_back(DecodeContext::THRESH_W, n+1,
k);
2552 to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2554 to_parse.emplace_back(DecodeContext::THRESH_E, n+1,
k);
2556 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2560 case DecodeContext::THRESH_E: {
2561 if (k < 1 || k > n || constructed.size() <
static_cast<size_t>(n))
return {};
2562 std::vector<NodeRef<Key>> subs;
2563 for (
int i = 0; i < n; ++i) {
2565 constructed.pop_back();
2566 subs.push_back(std::move(sub));
2568 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs),
k));
2571 case DecodeContext::ENDIF: {
2572 if (in >= last)
return {};
2577 to_parse.emplace_back(DecodeContext::ENDIF_ELSE, -1, -1);
2578 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2581 else if (in[0].first ==
OP_IF) {
2582 if (last - in >= 2 && in[1].first ==
OP_DUP) {
2584 to_parse.emplace_back(DecodeContext::DUP_IF, -1, -1);
2587 to_parse.emplace_back(DecodeContext::NON_ZERO, -1, -1);
2593 }
else if (in[0].first ==
OP_NOTIF) {
2595 to_parse.emplace_back(DecodeContext::ENDIF_NOTIF, -1, -1);
2602 case DecodeContext::ENDIF_NOTIF: {
2603 if (in >= last)
return {};
2606 to_parse.emplace_back(DecodeContext::OR_D, -1, -1);
2608 to_parse.emplace_back(DecodeContext::OR_C, -1, -1);
2611 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2614 case DecodeContext::ENDIF_ELSE: {
2615 if (in >= last)
return {};
2616 if (in[0].first ==
OP_IF) {
2618 BuildBack(ctx.MsContext(), Fragment::OR_I, constructed,
true);
2619 }
else if (in[0].first ==
OP_NOTIF) {
2621 to_parse.emplace_back(DecodeContext::ANDOR, -1, -1);
2623 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2631 if (constructed.size() != 1)
return {};
2633 tl_node->DuplicateKeyCheck(ctx);
2636 if (!tl_node->IsValidTopLevel())
return {};
2642template<
typename Ctx>
2644 return internal::Parse<typename Ctx::Key>(str, ctx);
2647template<
typename Ctx>
2649 using namespace internal;
2653 if (!decomposed)
return {};
2654 auto it = decomposed->begin();
2655 auto ret = DecodeScript<typename Ctx::Key>(it, decomposed->end(), ctx);
2656 if (!
ret)
return {};
2657 if (it != decomposed->end())
return {};
#define CHECK_NONFATAL(condition)
Identity function.
Serialized script, used inside transaction inputs and outputs.
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
uint160 RIPEMD160(std::span< const unsigned char > data)
Compute the 160-bit RIPEMD-160 hash of an array.
uint256 Hash(const T &in1)
Compute the 256-bit hash of an object.
std::string HexStr(const std::span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
@ TAPSCRIPT
Witness v1 with 32-byte program, not BIP16 P2SH-wrapped, script path spending, leaf version 0xc0; see...
static constexpr size_t TAPROOT_CONTROL_MAX_SIZE
#define CHECK(cond)
Unconditional failure on condition failure.
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.
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.
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...
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...
constexpr uint32_t P2WSH_TXOUT_BYTES
nValue + script len + OP_0 + pushdata 32.
int FindNextChar(std::span< const char > sp, const char m)
@ VERIFY
VERIFY wraps the top constructed node with v:
@ 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:
@ COMMA
COMMA expects the next element to be ',' and fails if not.
@ DUP_IF
DUP_IF wraps the top constructed node with d:
@ 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.
@ 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.
@ SINGLE_BKV_EXPR
A single expression of type B, K, or V.
@ 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,...
@ W_EXPR
An expression of type W (a: or s: wrappers).
@ THRESH_E
THRESH_E constructs a thresh node from the appropriate number of constructed children.
@ ENDIF
ENDIF signals that we are inside some sort of OP_IF structure, which could be or_d,...
@ 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.
std::optional< std::pair< std::vector< unsigned char >, int > > ParseHexStrEnd(std::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.
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< Key > Parse(std::span< const char > in, const Ctx &ctx)
Parse a miniscript from its textual descriptor form.
std::optional< std::pair< Key, int > > ParseKeyEnd(std::span< const char > in, const Ctx &ctx)
Parse a key string ending at the end of the fragment's text representation.
NodeRef< typename Ctx::Key > FromString(const std::string &str, const Ctx &ctx)
constexpr bool IsTapscript(MiniscriptContext ms_ctx)
Whether the context Tapscript, ensuring the only other possibility is P2WSH.
NodeRef< typename Ctx::Key > FromScript(const CScript &script, const Ctx &ctx)
NodeRef< Key > MakeNodeRef(Args &&... args)
Construct a miniscript node as a unique_ptr.
std::unique_ptr< const Node< Key > > NodeRef
std::pair< opcodetype, std::vector< unsigned char > > Opcode
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)
bool Const(const std::string &str, std::span< const char > &sp)
Parse a constant.
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.
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.
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)
const Node * FindInsaneSub() const
Find an insane subnode which has no insane children. Nullptr if there is none.
Node & operator=(const Node &)=delete
bool IsBKW() const
Whether this node is of type B, K or W.
NodeRef< Key > Clone() const
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 Node &)=delete
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< std::common_type_t< Args... > > Vector(Args &&... args)
Construct a vector with the specified elements.