5#ifndef BITCOIN_SCRIPT_MINISCRIPT_H
6#define BITCOIN_SCRIPT_MINISCRIPT_H
135 friend consteval Type operator""_mst(
const char* c,
size_t l);
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 Type sub0type =
subs.size() > 0 ?
subs[0]->GetType() :
""_mst;
602 template<
typename Result,
typename State,
typename DownFn,
typename UpFn>
603 std::optional<Result>
TreeEvalMaybe(State root_state, DownFn downfn, UpFn upfn)
const
612 StackElem(
const Node& node_,
size_t exp_, State&& state_) :
613 node(node_), expanded(exp_), state(std::move(state_)) {}
616 std::vector<StackElem> stack;
619 std::vector<Result> results;
620 stack.emplace_back(*
this, 0, std::move(root_state));
638 while (stack.size()) {
639 const Node&
node = stack.back().node;
640 if (stack.back().expanded <
node.subs.size()) {
644 size_t child_index = stack.back().expanded++;
645 State child_state = downfn(stack.back().state,
node, child_index);
646 stack.emplace_back(*
node.subs[child_index], 0, std::move(child_state));
651 std::optional<Result> result{upfn(std::move(stack.back().state),
node,
652 std::span<Result>{results}.last(
node.subs.size()))};
654 if (!result)
return {};
656 results.erase(results.end() -
node.subs.size(), results.end());
657 results.push_back(std::move(*result));
661 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{}; },
674 [&upfn](DummyState,
const Node&
node, std::span<Result>
subs) {
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),
688 [&upfn](State&& state,
const Node&
node, std::span<Result>
subs) {
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{}; },
703 [&upfn](DummyState,
const Node&
node, std::span<Result>
subs) {
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());
748 template<
typename Ctx>
767 switch (
node.fragment) {
781 if (
node.subs[0]->GetType() <<
"x"_mst) {
784 return std::move(
subs[0]);
801 for (
const auto& key :
node.keys) {
809 for (
auto it =
node.keys.begin() + 1; it !=
node.keys.end(); ++it) {
816 for (
size_t i = 1; i <
subs.size(); ++i) {
824 return TreeEval<CScript>(
false, downfn, upfn);
827 template<
typename CTx>
828 std::optional<std::string>
ToString(
const CTx& ctx)
const {
832 auto downfn = [](bool,
const Node&
node, size_t) {
844 auto upfn = [&ctx, is_tapscript](
bool wrapped,
const Node&
node, std::span<std::string>
subs) -> std::optional<std::string> {
845 std::string
ret = wrapped ?
":" :
"";
847 switch (
node.fragment) {
853 auto key_str = ctx.ToString(
node.subs[0]->keys[0]);
854 if (!key_str)
return {};
855 return std::move(
ret) +
"pk(" + std::move(*key_str) +
")";
859 auto key_str = ctx.ToString(
node.subs[0]->keys[0]);
860 if (!key_str)
return {};
861 return std::move(
ret) +
"pkh(" + std::move(*key_str) +
")";
863 return "c" + std::move(
subs[0]);
878 switch (
node.fragment) {
880 auto key_str = ctx.ToString(
node.keys[0]);
881 if (!key_str)
return {};
882 return std::move(
ret) +
"pk_k(" + std::move(*key_str) +
")";
885 auto key_str = ctx.ToString(
node.keys[0]);
886 if (!key_str)
return {};
887 return std::move(
ret) +
"pk_h(" + std::move(*key_str) +
")";
906 return std::move(
ret) +
"andor(" + std::move(
subs[0]) +
"," + std::move(
subs[1]) +
"," + std::move(
subs[2]) +
")";
910 for (
const auto& key :
node.keys) {
911 auto key_str = ctx.ToString(key);
912 if (!key_str)
return {};
913 str +=
"," + std::move(*key_str);
915 return std::move(str) +
")";
920 for (
const auto& key :
node.keys) {
921 auto key_str = ctx.ToString(key);
922 if (!key_str)
return {};
923 str +=
"," + std::move(*key_str);
925 return std::move(str) +
")";
929 for (
auto& sub :
subs) {
930 str +=
"," + std::move(sub);
932 return std::move(str) +
")";
939 return TreeEvalMaybe<std::string>(
false, downfn, upfn);
957 const auto count{1 +
subs[0]->ops.count +
subs[1]->ops.count};
958 const auto sat{
subs[0]->ops.sat +
subs[1]->ops.sat};
959 const auto dsat{
subs[0]->ops.dsat +
subs[1]->ops.dsat};
960 return {
count, sat, dsat};
963 const auto count{1 +
subs[0]->ops.count +
subs[1]->ops.count};
965 const auto dsat{
subs[0]->ops.dsat +
subs[1]->ops.dsat};
966 return {
count, sat, dsat};
969 const auto count{3 +
subs[0]->ops.count +
subs[1]->ops.count};
970 const auto sat{
subs[0]->ops.sat | (
subs[1]->ops.sat +
subs[0]->ops.dsat)};
971 const auto dsat{
subs[0]->ops.dsat +
subs[1]->ops.dsat};
972 return {
count, sat, dsat};
975 const auto count{2 +
subs[0]->ops.count +
subs[1]->ops.count};
976 const auto sat{
subs[0]->ops.sat | (
subs[1]->ops.sat +
subs[0]->ops.dsat)};
977 return {
count, sat, {}};
980 const auto count{3 +
subs[0]->ops.count +
subs[1]->ops.count};
981 const auto sat{
subs[0]->ops.sat |
subs[1]->ops.sat};
982 const auto dsat{
subs[0]->ops.dsat |
subs[1]->ops.dsat};
983 return {
count, sat, dsat};
986 const auto count{3 +
subs[0]->ops.count +
subs[1]->ops.count +
subs[2]->ops.count};
988 const auto dsat{
subs[0]->ops.dsat +
subs[2]->ops.dsat};
989 return {
count, sat, dsat};
1003 for (
const auto& sub :
subs) {
1004 count += sub->ops.count + 1;
1005 auto next_sats =
Vector(sats[0] + sub->ops.dsat);
1006 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub->ops.dsat) | (sats[j - 1] + sub->ops.sat));
1007 next_sats.push_back(sats[sats.size() - 1] + sub->ops.sat);
1008 sats = std::move(next_sats);
1011 return {
count, sats[
k], sats[0]};
1018 using namespace internal;
1034 const auto& x{subs[0]->ss};
1035 const auto& y{subs[1]->ss};
1036 const auto& z{subs[2]->ss};
1038 (x.sat + SatInfo::If() + y.sat) | (x.dsat + SatInfo::If() + z.sat),
1039 x.dsat + SatInfo::If() + z.dsat
1043 const auto& x{subs[0]->ss};
1044 const auto& y{subs[1]->ss};
1045 return {x.sat + y.sat, {}};
1048 const auto& x{subs[0]->ss};
1049 const auto& y{subs[1]->ss};
1050 return {x.sat + y.sat + SatInfo::BinaryOp(), x.dsat + y.dsat + SatInfo::BinaryOp()};
1053 const auto& x{subs[0]->ss};
1054 const auto& y{subs[1]->ss};
1056 ((x.sat + y.dsat) | (x.dsat + y.sat)) + SatInfo::BinaryOp(),
1057 x.dsat + y.dsat + SatInfo::BinaryOp()
1061 const auto& x{subs[0]->ss};
1062 const auto& y{subs[1]->ss};
1063 return {(x.sat + SatInfo::If()) | (x.dsat + SatInfo::If() + y.sat), {}};
1066 const auto& x{subs[0]->ss};
1067 const auto& y{subs[1]->ss};
1074 const auto& x{subs[0]->ss};
1075 const auto& y{subs[1]->ss};
1076 return {SatInfo::If() + (x.sat | y.sat), SatInfo::If() + (x.dsat | y.dsat)};
1105 auto sats =
Vector(SatInfo::Empty());
1106 for (
size_t i = 0; i < subs.size(); ++i) {
1109 auto add = i ? SatInfo::BinaryOp() : SatInfo::Empty();
1111 auto next_sats =
Vector(sats[0] + subs[i]->ss.dsat + add);
1113 for (
size_t j = 1; j < sats.size(); ++j) {
1114 next_sats.push_back(((sats[j] + subs[i]->ss.dsat) | (sats[j - 1] + subs[i]->ss.sat)) + add);
1117 next_sats.push_back(sats[sats.size() - 1] + subs[i]->ss.sat + add);
1119 sats = std::move(next_sats);
1134 const uint32_t pubkey_size =
IsTapscript(m_script_ctx) ? 1 + 32 : 1 + 33;
1147 const auto sat{(subs[0]->ws.sat + subs[1]->ws.sat) | (subs[0]->ws.dsat + subs[2]->ws.sat)};
1148 const auto dsat{subs[0]->ws.dsat + subs[2]->ws.dsat};
1152 case Fragment::AND_B:
return {subs[0]->ws.sat + subs[1]->ws.sat, subs[0]->ws.dsat + subs[1]->ws.dsat};
1154 const auto sat{(subs[0]->ws.dsat + subs[1]->ws.sat) | (subs[0]->ws.sat + subs[1]->ws.dsat)};
1155 const auto dsat{subs[0]->ws.dsat + subs[1]->ws.dsat};
1158 case Fragment::OR_C:
return {subs[0]->ws.sat | (subs[0]->ws.dsat + subs[1]->ws.sat), {}};
1159 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};
1160 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)};
1172 for (
const auto& sub : subs) {
1173 auto next_sats =
Vector(sats[0] + sub->ws.dsat);
1174 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub->ws.dsat) | (sats[j - 1] + sub->ws.sat));
1175 next_sats.push_back(sats[sats.size() - 1] + sub->ws.sat);
1176 sats = std::move(next_sats);
1179 return {sats[
k], sats[0]};
1185 template<
typename Ctx>
1187 using namespace internal;
1191 auto helper = [&ctx](
const Node&
node, std::span<InputResult> subres) -> InputResult {
1192 switch (
node.fragment) {
1194 std::vector<unsigned char> sig;
1196 return {
ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
1199 std::vector<unsigned char> key = ctx.ToPKBytes(
node.keys[0]), sig;
1201 return {
ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
1207 for (
size_t i = 0; i <
node.keys.size(); ++i) {
1210 std::vector<unsigned char> sig;
1213 auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1217 std::vector<InputStack> next_sats;
1218 next_sats.push_back(sats[0] +
ZERO);
1219 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] +
ZERO) | (std::move(sats[j - 1]) + sat));
1220 next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1222 sats = std::move(next_sats);
1226 auto& nsat{sats[0]};
1229 return {std::move(nsat), std::move(sats[
node.k])};
1236 for (
size_t i = 0; i <
node.keys.size(); ++i) {
1237 std::vector<unsigned char> sig;
1240 auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1244 std::vector<InputStack> next_sats;
1245 next_sats.push_back(sats[0]);
1246 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
1247 next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1249 sats = std::move(next_sats);
1252 InputStack nsat =
ZERO;
1253 for (
size_t i = 0; i <
node.k; ++i) nsat = std::move(nsat) +
ZERO;
1255 return {std::move(nsat), std::move(sats[
node.k])};
1262 for (
size_t i = 0; i < subres.size(); ++i) {
1264 auto& res = subres[subres.size() - i - 1];
1268 std::vector<InputStack> next_sats;
1269 next_sats.push_back(sats[0] + res.nsat);
1270 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + res.nsat) | (std::move(sats[j - 1]) + res.sat));
1271 next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
1273 sats = std::move(next_sats);
1277 InputStack nsat = INVALID;
1278 for (
size_t i = 0; i < sats.size(); ++i) {
1285 if (i != 0 && i !=
node.k) sats[i].SetMalleable().SetNonCanon();
1287 if (i !=
node.k) nsat = std::move(nsat) | std::move(sats[i]);
1290 return {std::move(nsat), std::move(sats[
node.k])};
1293 return {INVALID, ctx.CheckOlder(
node.k) ?
EMPTY : INVALID};
1296 return {INVALID, ctx.CheckAfter(
node.k) ?
EMPTY : INVALID};
1299 std::vector<unsigned char> preimage;
1301 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1304 std::vector<unsigned char> preimage;
1306 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1309 std::vector<unsigned char> preimage;
1311 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1314 std::vector<unsigned char> preimage;
1316 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1319 auto& x = subres[0], &y = subres[1];
1326 return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
1329 auto& x = subres[0], &y = subres[1];
1335 return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
1338 auto& x = subres[0], &z = subres[1];
1340 return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
1343 auto& x = subres[0], &z = subres[1];
1344 return {INVALID, std::move(x.sat) | (z.sat + x.nsat)};
1347 auto& x = subres[0], &z = subres[1];
1348 return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
1351 auto& x = subres[0], &z = subres[1];
1352 return {(x.nsat + ONE) | (z.nsat +
ZERO), (x.sat + ONE) | (z.sat +
ZERO)};
1355 auto& x = subres[0], &y = subres[1], &z = subres[2];
1356 return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
1362 return std::move(subres[0]);
1364 auto &x = subres[0];
1365 return {
ZERO, x.sat + ONE};
1368 auto &x = subres[0];
1374 return {InputStack(
ZERO).SetMalleable(x.nsat.available !=
Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
1377 auto &x = subres[0];
1378 return {INVALID, std::move(x.sat)};
1384 return {INVALID, INVALID};
1387 auto tester = [&helper](
const Node&
node, std::span<InputResult> subres) -> InputResult {
1388 auto ret = helper(
node, subres);
1430 return TreeEval<InputResult>(tester);
1445 Comp(
const Ctx& ctx) : ctx_ptr(&ctx) {}
1446 bool operator()(
const Key& a,
const Key& b)
const {
return ctx_ptr->KeyCompare(a, b); }
1452 using keyset = std::set<Key, Comp>;
1453 using state = std::optional<keyset>;
1455 auto upfn = [&ctx](
const Node&
node, std::span<state> subs) -> state {
1457 if (
node.has_duplicate_keys.has_value() && *
node.has_duplicate_keys)
return {};
1460 for (
auto& sub : subs) {
1461 if (!sub.has_value()) {
1462 node.has_duplicate_keys =
true;
1469 size_t keys_count =
node.keys.size();
1470 keyset key_set{
node.keys.begin(),
node.keys.end(), Comp(ctx)};
1471 if (key_set.size() != keys_count) {
1473 node.has_duplicate_keys =
true;
1478 for (
auto& sub : subs) {
1479 keys_count += sub->size();
1482 if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1483 key_set.merge(*sub);
1484 if (key_set.size() != keys_count) {
1485 node.has_duplicate_keys =
true;
1490 node.has_duplicate_keys =
false;
1494 TreeEval<state>(upfn);
1502 if (!ops.sat.valid)
return {};
1503 return ops.count + ops.sat.value;
1518 return !((GetType() &
"BKW"_mst) ==
""_mst);
1523 if (!ss.sat.valid)
return {};
1524 return ss.sat.netdiff +
static_cast<int32_t
>(IsBKW());
1529 if (!ss.sat.valid)
return {};
1530 return ss.sat.exec +
static_cast<int32_t
>(IsBKW());
1538 if (
const auto exec_ss = GetExecStackSize())
return exec_ss <=
MAX_STACK_SIZE;
1551 if (!ws.sat.valid)
return {};
1552 return ws.sat.value;
1563 return TreeEval<const Node*>([](
const Node&
node, std::span<const Node*> subs) ->
const Node* {
1564 for (
auto& sub: subs)
if (sub)
return sub;
1565 if (!
node.IsSaneSubexpression())
return &
node;
1572 template<
typename F>
1576 return TreeEval<int>([&fn](
const Node&
node, std::span<int> subs) ->
bool {
1577 switch (
node.fragment) {
1578 case Fragment::JUST_0:
1580 case Fragment::JUST_1:
1582 case Fragment::PK_K:
1583 case Fragment::PK_H:
1584 case Fragment::MULTI:
1585 case Fragment::MULTI_A:
1586 case Fragment::AFTER:
1587 case Fragment::OLDER:
1588 case Fragment::HASH256:
1589 case Fragment::HASH160:
1590 case Fragment::SHA256:
1591 case Fragment::RIPEMD160:
1592 return bool{fn(node)};
1594 return (subs[0] && subs[1]) || subs[2];
1597 return subs[0] && subs[1];
1602 return subs[0] || subs[1];
1604 return static_cast<uint32_t
>(
std::count(subs.begin(), subs.end(),
true)) >=
node.k;
1606 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>
1751std::optional<std::pair<Key, int>>
ParseKeyEnd(std::span<const char> in,
const Ctx& 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>
1762std::optional<std::pair<std::vector<unsigned char>,
int>>
ParseHexStrEnd(std::span<const char> in,
const size_t expected_size,
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 = [&](std::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);
2162 assert(constructed[0]->ScriptSize() == script_size);
2163 if (in.size() > 0)
return {};
2165 tl_node->DuplicateKeyCheck(ctx);
2251template<
typename Key,
typename Ctx,
typename I>
2255 std::vector<std::tuple<DecodeContext, int64_t, int64_t>> to_parse;
2256 std::vector<NodeRef<Key>> constructed;
2260 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2262 while (!to_parse.empty()) {
2264 if (!constructed.empty() && !constructed.back()->IsValid())
return {};
2267 auto [cur_context, n,
k] = to_parse.back();
2268 to_parse.pop_back();
2270 switch(cur_context) {
2271 case DecodeContext::SINGLE_BKV_EXPR: {
2272 if (in >= last)
return {};
2275 if (in[0].first ==
OP_1) {
2277 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1));
2280 if (in[0].first ==
OP_0) {
2282 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0));
2286 if (in[0].second.size() == 33 || in[0].second.size() == 32) {
2287 auto key = ctx.FromPKBytes(in[0].second.begin(), in[0].second.end());
2288 if (!key)
return {};
2294 auto key = ctx.FromPKHBytes(in[2].second.begin(), in[2].second.end());
2295 if (!key)
return {};
2301 std::optional<int64_t> num;
2304 if (*num < 1 || *num > 0x7FFFFFFFL)
return {};
2305 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num));
2310 if (num < 1 || num > 0x7FFFFFFFL)
return {};
2311 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num));
2316 if (in[2].first ==
OP_SHA256 && in[1].second.size() == 32) {
2317 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, in[1].second));
2320 }
else if (in[2].first ==
OP_RIPEMD160 && in[1].second.size() == 20) {
2324 }
else if (in[2].first ==
OP_HASH256 && in[1].second.size() == 32) {
2325 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, in[1].second));
2328 }
else if (in[2].first ==
OP_HASH160 && in[1].second.size() == 20) {
2329 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, in[1].second));
2337 std::vector<Key> keys;
2339 if (!n || last - in < 3 + *n)
return {};
2340 if (*n < 1 || *n > 20)
return {};
2341 for (
int i = 0; i < *n; ++i) {
2342 if (in[2 + i].second.size() != 33)
return {};
2343 auto key = ctx.FromPKBytes(in[2 + i].second.begin(), in[2 + i].second.end());
2344 if (!key)
return {};
2345 keys.push_back(std::move(*key));
2348 if (!
k || *k < 1 || *k > *n)
return {};
2350 std::reverse(keys.begin(), keys.end());
2351 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), *
k));
2355 if (last - in >= 4 && in[0].first ==
OP_NUMEQUAL) {
2361 if (last - in < 2 + *
k * 2)
return {};
2362 std::vector<Key> keys;
2365 for (
int pos = 2;; pos += 2) {
2366 if (last - in < pos + 2)
return {};
2369 if (in[pos + 1].second.size() != 32)
return {};
2370 auto key = ctx.FromPKBytes(in[pos + 1].second.begin(), in[pos + 1].second.end());
2371 if (!key)
return {};
2372 keys.push_back(std::move(*key));
2378 if (keys.size() < (
size_t)*
k)
return {};
2379 in += 2 + keys.size() * 2;
2380 std::reverse(keys.begin(), keys.end());
2381 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), *
k));
2391 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2397 to_parse.emplace_back(DecodeContext::VERIFY, -1, -1);
2398 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2404 to_parse.emplace_back(DecodeContext::ZERO_NOTEQUAL, -1, -1);
2405 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2410 if (*num < 1)
return {};
2412 to_parse.emplace_back(DecodeContext::THRESH_W, 0, *num);
2418 to_parse.emplace_back(DecodeContext::ENDIF, -1, -1);
2419 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2430 to_parse.emplace_back(DecodeContext::AND_B, -1, -1);
2431 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2432 to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2438 to_parse.emplace_back(DecodeContext::OR_B, -1, -1);
2439 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2440 to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2446 case DecodeContext::BKV_EXPR: {
2447 to_parse.emplace_back(DecodeContext::MAYBE_AND_V, -1, -1);
2448 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2451 case DecodeContext::W_EXPR: {
2453 if (in >= last)
return {};
2456 to_parse.emplace_back(DecodeContext::ALT, -1, -1);
2458 to_parse.emplace_back(DecodeContext::SWAP, -1, -1);
2460 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2463 case DecodeContext::MAYBE_AND_V: {
2467 to_parse.emplace_back(DecodeContext::AND_V, -1, -1);
2469 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2473 case DecodeContext::SWAP: {
2474 if (in >= last || in[0].first !=
OP_SWAP || constructed.empty())
return {};
2476 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S,
Vector(std::move(constructed.back())));
2479 case DecodeContext::ALT: {
2480 if (in >= last || in[0].first !=
OP_TOALTSTACK || constructed.empty())
return {};
2482 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A,
Vector(std::move(constructed.back())));
2486 if (constructed.empty())
return {};
2487 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C,
Vector(std::move(constructed.back())));
2490 case DecodeContext::DUP_IF: {
2491 if (constructed.empty())
return {};
2492 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D,
Vector(std::move(constructed.back())));
2495 case DecodeContext::VERIFY: {
2496 if (constructed.empty())
return {};
2497 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V,
Vector(std::move(constructed.back())));
2500 case DecodeContext::NON_ZERO: {
2501 if (constructed.empty())
return {};
2502 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J,
Vector(std::move(constructed.back())));
2505 case DecodeContext::ZERO_NOTEQUAL: {
2506 if (constructed.empty())
return {};
2507 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N,
Vector(std::move(constructed.back())));
2510 case DecodeContext::AND_V: {
2511 if (constructed.size() < 2)
return {};
2512 BuildBack(ctx.MsContext(), Fragment::AND_V, constructed,
true);
2515 case DecodeContext::AND_B: {
2516 if (constructed.size() < 2)
return {};
2517 BuildBack(ctx.MsContext(), Fragment::AND_B, constructed,
true);
2520 case DecodeContext::OR_B: {
2521 if (constructed.size() < 2)
return {};
2522 BuildBack(ctx.MsContext(), Fragment::OR_B, constructed,
true);
2525 case DecodeContext::OR_C: {
2526 if (constructed.size() < 2)
return {};
2527 BuildBack(ctx.MsContext(), Fragment::OR_C, constructed,
true);
2530 case DecodeContext::OR_D: {
2531 if (constructed.size() < 2)
return {};
2532 BuildBack(ctx.MsContext(), Fragment::OR_D, constructed,
true);
2535 case DecodeContext::ANDOR: {
2536 if (constructed.size() < 3)
return {};
2538 constructed.pop_back();
2540 constructed.pop_back();
2542 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR,
Vector(std::move(left), std::move(mid), std::move(right)));
2545 case DecodeContext::THRESH_W: {
2546 if (in >= last)
return {};
2547 if (in[0].first ==
OP_ADD) {
2549 to_parse.emplace_back(DecodeContext::THRESH_W, n+1,
k);
2550 to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2552 to_parse.emplace_back(DecodeContext::THRESH_E, n+1,
k);
2554 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2558 case DecodeContext::THRESH_E: {
2559 if (k < 1 || k > n || constructed.size() <
static_cast<size_t>(n))
return {};
2560 std::vector<NodeRef<Key>> subs;
2561 for (
int i = 0; i < n; ++i) {
2563 constructed.pop_back();
2564 subs.push_back(std::move(sub));
2566 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs),
k));
2569 case DecodeContext::ENDIF: {
2570 if (in >= last)
return {};
2575 to_parse.emplace_back(DecodeContext::ENDIF_ELSE, -1, -1);
2576 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2579 else if (in[0].first ==
OP_IF) {
2580 if (last - in >= 2 && in[1].first ==
OP_DUP) {
2582 to_parse.emplace_back(DecodeContext::DUP_IF, -1, -1);
2585 to_parse.emplace_back(DecodeContext::NON_ZERO, -1, -1);
2591 }
else if (in[0].first ==
OP_NOTIF) {
2593 to_parse.emplace_back(DecodeContext::ENDIF_NOTIF, -1, -1);
2600 case DecodeContext::ENDIF_NOTIF: {
2601 if (in >= last)
return {};
2604 to_parse.emplace_back(DecodeContext::OR_D, -1, -1);
2606 to_parse.emplace_back(DecodeContext::OR_C, -1, -1);
2609 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2612 case DecodeContext::ENDIF_ELSE: {
2613 if (in >= last)
return {};
2614 if (in[0].first ==
OP_IF) {
2616 BuildBack(ctx.MsContext(), Fragment::OR_I, constructed,
true);
2617 }
else if (in[0].first ==
OP_NOTIF) {
2619 to_parse.emplace_back(DecodeContext::ANDOR, -1, -1);
2621 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2629 if (constructed.size() != 1)
return {};
2631 tl_node->DuplicateKeyCheck(ctx);
2634 if (!tl_node->IsValidTopLevel())
return {};
2640template<
typename Ctx>
2642 return internal::Parse<typename Ctx::Key>(str, ctx);
2645template<
typename Ctx>
2647 using namespace internal;
2651 if (!decomposed)
return {};
2652 auto it = decomposed->begin();
2653 auto ret = DecodeScript<typename Ctx::Key>(it, decomposed->end(), ctx);
2654 if (!
ret)
return {};
2655 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.
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(uint32_t flags)
Internal constructor used by the ""_mst operator.
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.
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, bool skip)
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.