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();
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,
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);
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();
1112 auto next_sats =
Vector(sats[0] + subs[i]->ss.dsat + add);
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);
1135 const uint32_t pubkey_size =
IsTapscript(m_script_ctx) ? 1 + 32 : 1 + 33;
1148 const auto sat{(subs[0]->ws.sat + subs[1]->ws.sat) | (subs[0]->ws.dsat + subs[2]->ws.sat)};
1149 const auto dsat{subs[0]->ws.dsat + subs[2]->ws.dsat};
1153 case Fragment::AND_B:
return {subs[0]->ws.sat + subs[1]->ws.sat, subs[0]->ws.dsat + subs[1]->ws.dsat};
1155 const auto sat{(subs[0]->ws.dsat + subs[1]->ws.sat) | (subs[0]->ws.sat + subs[1]->ws.dsat)};
1156 const auto dsat{subs[0]->ws.dsat + subs[1]->ws.dsat};
1159 case Fragment::OR_C:
return {subs[0]->ws.sat | (subs[0]->ws.dsat + subs[1]->ws.sat), {}};
1160 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};
1161 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)};
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);
1503 if (!ops.sat.valid)
return {};
1504 return ops.count + ops.sat.value;
1519 return !((GetType() &
"BKW"_mst) ==
""_mst);
1524 if (!ss.sat.valid)
return {};
1525 return ss.sat.netdiff +
static_cast<int32_t
>(IsBKW());
1530 if (!ss.sat.valid)
return {};
1531 return ss.sat.exec +
static_cast<int32_t
>(IsBKW());
1539 if (
const auto exec_ss = GetExecStackSize())
return exec_ss <=
MAX_STACK_SIZE;
1552 if (!ws.sat.valid)
return {};
1553 return ws.sat.value;
1565 for (
auto& sub: subs)
if (sub)
return sub;
1566 if (!
node.IsSaneSubexpression())
return &
node;
1573 template<
typename F>
1578 switch (
node.fragment) {
1579 case Fragment::JUST_0:
1581 case Fragment::JUST_1:
1583 case Fragment::PK_K:
1584 case Fragment::PK_H:
1585 case Fragment::MULTI:
1586 case Fragment::MULTI_A:
1587 case Fragment::AFTER:
1588 case Fragment::OLDER:
1589 case Fragment::HASH256:
1590 case Fragment::HASH160:
1591 case Fragment::SHA256:
1592 case Fragment::RIPEMD160:
1593 return bool{fn(node)};
1595 return (subs[0] && subs[1]) || subs[2];
1598 return subs[0] && subs[1];
1603 return subs[0] || subs[1];
1605 return static_cast<uint32_t
>(
std::count(subs.begin(), subs.end(),
true)) >=
node.k;
1607 assert(subs.size() == 1);
1615 if (GetType() ==
""_mst)
return false;
1638 bool IsSaneSubexpression()
const {
return ValidSatisfactions() && IsNonMalleable() && CheckTimeLocksMix() && CheckDuplicateKey(); }
1641 bool IsSane()
const {
return IsValidTopLevel() && IsSaneSubexpression() && NeedsSignature(); }
1647 template<
typename Ctx>
1648 Availability Satisfy(
const Ctx& ctx, std::vector<std::vector<unsigned char>>& stack,
bool nonmalleable =
true)
const {
1649 auto ret = ProduceInput(ctx);
1650 if (nonmalleable && (
ret.sat.malleable || !
ret.sat.has_sig))
return Availability::NO;
1651 stack = std::move(
ret.sat.stack);
1652 return ret.sat.available;
1660 : 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()) {}
1662 : fragment(nt),
k(val),
data(
std::move(arg)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1664 : 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()) {}
1666 : fragment(nt),
k(val), keys(
std::move(key)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1668 : fragment(nt),
k(val), subs(
std::move(sub)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1670 : fragment(nt),
k(val), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
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)
1676 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(arg), val) { DuplicateKeyCheck(ctx);}
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)
1684 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt, val) { DuplicateKeyCheck(ctx); }
1750template<
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}};
1761template<
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}};
1775template<
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)));
1792template<
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 {
1819 const auto required_ctx{is_multi_a ? MiniscriptContext::TAPSCRIPT : MiniscriptContext::P2WSH};
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;
1844 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys),
k));
1846 script_size += 2 + (keys.size() > 16) + (
k > 16) + 34 * keys.size();
1847 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys),
k));
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') {
1905 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0));
1906 to_parse.emplace_back(ParseContext::OR_I, -1, -1);
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)) {
1918 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0));
1919 }
else if (
Const(
"1", in)) {
1920 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1));
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;
1953 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, std::move(hash)));
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;
1967 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, std::move(hash)));
1968 in = in.
subspan(hash_size + 1);
1970 }
else if (
Const(
"hash160(", in)) {
1972 if (!res)
return {};
1973 auto& [hash, hash_size] = *res;
1974 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, std::move(hash)));
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 {};
1982 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num));
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 {};
1990 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num));
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);
2004 to_parse.emplace_back(ParseContext::THRESH, 1, *
k);
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)) {
2008 to_parse.emplace_back(ParseContext::ANDOR, -1, -1);
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)) {
2021 to_parse.emplace_back(ParseContext::AND_B, -1, -1);
2023 }
else if (
Const(
"and_v(", in)) {
2024 to_parse.emplace_back(ParseContext::AND_V, -1, -1);
2026 }
else if (
Const(
"or_b(", in)) {
2027 to_parse.emplace_back(ParseContext::OR_B, -1, -1);
2029 }
else if (
Const(
"or_c(", in)) {
2030 to_parse.emplace_back(ParseContext::OR_C, -1, -1);
2032 }
else if (
Const(
"or_d(", in)) {
2033 to_parse.emplace_back(ParseContext::OR_D, -1, -1);
2035 }
else if (
Const(
"or_i(", in)) {
2036 to_parse.emplace_back(ParseContext::OR_I, -1, -1);
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: {
2049 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A,
Vector(std::move(constructed.back())));
2052 case ParseContext::SWAP: {
2053 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S,
Vector(std::move(constructed.back())));
2057 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C,
Vector(std::move(constructed.back())));
2060 case ParseContext::DUP_IF: {
2061 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D,
Vector(std::move(constructed.back())));
2064 case ParseContext::NON_ZERO: {
2065 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J,
Vector(std::move(constructed.back())));
2068 case ParseContext::ZERO_NOTEQUAL: {
2069 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N,
Vector(std::move(constructed.back())));
2072 case ParseContext::VERIFY: {
2073 script_size += (constructed.back()->GetType() <<
"x"_mst);
2074 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V,
Vector(std::move(constructed.back())));
2077 case ParseContext::WRAP_U: {
2081 case ParseContext::WRAP_T: {
2085 case ParseContext::AND_B: {
2086 BuildBack(ctx.MsContext(), Fragment::AND_B, constructed);
2089 case ParseContext::AND_N: {
2090 auto mid = std::move(constructed.back());
2091 constructed.pop_back();
2092 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)));
2095 case ParseContext::AND_V: {
2096 BuildBack(ctx.MsContext(), Fragment::AND_V, constructed);
2099 case ParseContext::OR_B: {
2100 BuildBack(ctx.MsContext(), Fragment::OR_B, constructed);
2103 case ParseContext::OR_C: {
2104 BuildBack(ctx.MsContext(), Fragment::OR_C, constructed);
2107 case ParseContext::OR_D: {
2108 BuildBack(ctx.MsContext(), Fragment::OR_D, constructed);
2111 case ParseContext::OR_I: {
2112 BuildBack(ctx.MsContext(), Fragment::OR_I, constructed);
2115 case ParseContext::ANDOR: {
2116 auto right = std::move(constructed.back());
2117 constructed.pop_back();
2118 auto mid = std::move(constructed.back());
2119 constructed.pop_back();
2120 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR,
Vector(std::move(constructed.back()), std::move(mid), std::move(right)));
2123 case ParseContext::THRESH: {
2124 if (in.
size() < 1)
return {};
2127 to_parse.emplace_back(ParseContext::THRESH, n+1,
k);
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());
2140 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs),
k));
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);
2161 assert(constructed[0]->ScriptSize() == script_size);
2162 if (in.
size() > 0)
return {};
2164 tl_node->DuplicateKeyCheck(ctx);
2250template<
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) {
2276 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1));
2279 if (in[0].first ==
OP_0) {
2281 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_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 {};
2304 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num));
2309 if (num < 1 || num > 0x7FFFFFFFL)
return {};
2310 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num));
2315 if (in[2].first ==
OP_SHA256 && in[1].second.size() == 32) {
2316 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, in[1].second));
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) {
2324 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, in[1].second));
2327 }
else if (in[2].first ==
OP_HASH160 && in[1].second.size() == 20) {
2328 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, in[1].second));
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());
2350 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), *
k));
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());
2380 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), *
k));
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);
2429 to_parse.emplace_back(DecodeContext::AND_B, -1, -1);
2430 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2431 to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2437 to_parse.emplace_back(DecodeContext::OR_B, -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: {
2466 to_parse.emplace_back(DecodeContext::AND_V, -1, -1);
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 {};
2475 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S,
Vector(std::move(constructed.back())));
2478 case DecodeContext::ALT: {
2479 if (in >= last || in[0].first !=
OP_TOALTSTACK || constructed.empty())
return {};
2481 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A,
Vector(std::move(constructed.back())));
2485 if (constructed.empty())
return {};
2486 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C,
Vector(std::move(constructed.back())));
2489 case DecodeContext::DUP_IF: {
2490 if (constructed.empty())
return {};
2491 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D,
Vector(std::move(constructed.back())));
2494 case DecodeContext::VERIFY: {
2495 if (constructed.empty())
return {};
2496 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V,
Vector(std::move(constructed.back())));
2499 case DecodeContext::NON_ZERO: {
2500 if (constructed.empty())
return {};
2501 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J,
Vector(std::move(constructed.back())));
2504 case DecodeContext::ZERO_NOTEQUAL: {
2505 if (constructed.empty())
return {};
2506 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N,
Vector(std::move(constructed.back())));
2509 case DecodeContext::AND_V: {
2510 if (constructed.size() < 2)
return {};
2511 BuildBack(ctx.MsContext(), Fragment::AND_V, constructed,
true);
2514 case DecodeContext::AND_B: {
2515 if (constructed.size() < 2)
return {};
2516 BuildBack(ctx.MsContext(), Fragment::AND_B, constructed,
true);
2519 case DecodeContext::OR_B: {
2520 if (constructed.size() < 2)
return {};
2521 BuildBack(ctx.MsContext(), Fragment::OR_B, constructed,
true);
2524 case DecodeContext::OR_C: {
2525 if (constructed.size() < 2)
return {};
2526 BuildBack(ctx.MsContext(), Fragment::OR_C, constructed,
true);
2529 case DecodeContext::OR_D: {
2530 if (constructed.size() < 2)
return {};
2531 BuildBack(ctx.MsContext(), Fragment::OR_D, constructed,
true);
2534 case DecodeContext::ANDOR: {
2535 if (constructed.size() < 3)
return {};
2537 constructed.pop_back();
2539 constructed.pop_back();
2541 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR,
Vector(std::move(left), std::move(mid), std::move(right)));
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));
2565 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs),
k));
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 {};
2603 to_parse.emplace_back(DecodeContext::OR_D, -1, -1);
2605 to_parse.emplace_back(DecodeContext::OR_C, -1, -1);
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) {
2615 BuildBack(ctx.MsContext(), Fragment::OR_I, constructed,
true);
2616 }
else if (in[0].first ==
OP_NOTIF) {
2618 to_parse.emplace_back(DecodeContext::ANDOR, -1, -1);
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 {};
2639template<
typename Ctx>
2641 return internal::Parse<typename Ctx::Key>(str, ctx);
2644template<
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 {};
#define CHECK_NONFATAL(condition)
Identity function.
Serialized script, used inside transaction inputs and outputs.
A Span is an object that can refer to a contiguous sequence of objects.
CONSTEXPR_IF_NOT_DEBUG Span< C > last(std::size_t count) const noexcept
constexpr std::size_t size() const noexcept
CONSTEXPR_IF_NOT_DEBUG Span< C > subspan(std::size_t offset) const noexcept
constexpr C * data() const noexcept
constexpr C * begin() const noexcept
This type encapsulates the miniscript type system properties.
static consteval Type Make(uint32_t flags) noexcept
Construction function used by the ""_mst operator.
constexpr bool operator<<(Type x) const
Check whether the left hand's properties are superset of the right's (= left is a subtype of right).
uint32_t m_flags
Internal bitmap of properties (see ""_mst operator for details).
constexpr Type If(bool x) const
The empty type if x is false, itself otherwise.
constexpr Type operator&(Type x) const
Compute the type with the intersection of properties.
constexpr bool operator<(Type x) const
Comparison operator to enable use in sets/maps (total ordering incompatible with <<).
constexpr Type operator|(Type x) const
Compute the type with the union of properties.
constexpr bool operator==(Type x) const
Equality operator.
constexpr Type(uint32_t flags) noexcept
Internal constructor.
static const int WITNESS_SCALE_FACTOR
uint160 RIPEMD160(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 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.
int FindNextChar(Span< const char > sp, const char m)
std::optional< int64_t > ParseScriptNumber(const Opcode &in)
Determine whether the passed pair (created by DecomposeScript) is pushing a number.
Type SanitizeType(Type e)
A helper sanitizer/checker for the output of CalcType.
std::optional< std::vector< Opcode > > DecomposeScript(const CScript &script)
Decode a script into opcode/push pairs.
NodeRef< Key > DecodeScript(I &in, I last, const Ctx &ctx)
Parse a miniscript from a bitcoin script.
NodeRef< Key > Parse(Span< const char > in, const Ctx &ctx)
Parse a miniscript from its textual descriptor form.
constexpr uint32_t TX_BODY_LEEWAY_WEIGHT
Data other than the witness in a transaction. Overhead + vin count + one vin + vout count + one vout ...
constexpr uint32_t TXIN_BYTES_NO_WITNESS
prevout + nSequence + scriptSig
static const auto ONE
A stack consisting of a single 0x01 element (interpreted as 1 by the script interpreted in numeric co...
static const auto ZERO32
A stack consisting of a single malleable 32-byte 0x0000...0000 element (for dissatisfying hash challe...
std::optional< std::pair< std::vector< unsigned char >, int > > ParseHexStrEnd(Span< const char > in, const size_t expected_size, const Ctx &ctx)
Parse a hex string ending at the end of the fragment's text representation.
constexpr uint32_t MaxScriptSize(MiniscriptContext ms_ctx)
The maximum size of a script depending on the context.
constexpr uint32_t TX_OVERHEAD
version + nLockTime
static const auto ZERO
A stack consisting of a single zero-length element (interpreted as 0 by the script interpreter in num...
std::optional< std::pair< Key, int > > ParseKeyEnd(Span< const char > in, const Ctx &ctx)
Parse a key string ending at the end of the fragment's text representation.
constexpr uint32_t P2WSH_TXOUT_BYTES
nValue + script len + OP_0 + pushdata 32.
@ 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.
Type ComputeType(Fragment fragment, Type x, Type y, Type z, const std::vector< Type > &sub_types, uint32_t k, size_t data_size, size_t n_subs, size_t n_keys, MiniscriptContext ms_ctx)
Helper function for Node::CalcType.
void BuildBack(const MiniscriptContext script_ctx, Fragment nt, std::vector< NodeRef< Key > > &constructed, const bool reverse=false)
BuildBack pops the last two elements off constructed and wraps them in the specified Fragment.
static constexpr uint32_t MAX_TAPMINISCRIPT_STACK_ELEM_SIZE
The maximum size of a witness item for a Miniscript under Tapscript context. (A BIP340 signature with...
NodeRef< typename Ctx::Key > FromString(const std::string &str, const Ctx &ctx)
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, 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< typename std::common_type< Args... >::type > Vector(Args &&... args)
Construct a vector with the specified elements.