5#ifndef BITCOIN_SCRIPT_MINISCRIPT_H
6#define BITCOIN_SCRIPT_MINISCRIPT_H
137 friend consteval Type operator""_mst(
const char* c,
size_t l);
159inline consteval Type operator""_mst(
const char* c,
size_t l)
163 for (
const char *p = c; p < c + l; p++) {
175 *p ==
'f' ? 1 << 10 :
176 *p ==
's' ? 1 << 11 :
177 *p ==
'm' ? 1 << 12 :
178 *p ==
'x' ? 1 << 13 :
179 *p ==
'g' ? 1 << 14 :
180 *p ==
'h' ? 1 << 15 :
181 *p ==
'i' ? 1 << 16 :
182 *p ==
'j' ? 1 << 17 :
183 *p ==
'k' ? 1 << 18 :
184 (
throw std::logic_error(
"Unknown character in _mst literal"), 0)
191using Opcode = std::pair<opcodetype, std::vector<unsigned char>>;
193template<
typename Key>
struct Node;
194template<
typename Key>
using NodeRef = std::unique_ptr<const Node<Key>>;
197template<
typename Key,
typename... Args>
201template <
typename Key, std::invocable<const Node<Key>&> Fn>
204 std::vector<std::reference_wrapper<const Node<Key>>> stack{root};
205 while (!stack.empty()) {
207 std::invoke(fn,
node);
209 for (
const auto& sub :
node.subs) {
210 stack.emplace_back(*sub);
328 std::vector<std::vector<unsigned char>>
stack;
362 template<
typename A,
typename B>
381 if (!a.
valid)
return b;
382 if (!b.
valid)
return a;
451 constexpr SatInfo(int32_t in_netdiff, int32_t in_exec) noexcept :
458 if (!a.valid)
return b;
459 if (!b.valid)
return a;
461 return {std::max(a.netdiff, b.netdiff), std::max(a.exec, b.exec)};
468 if (!a.valid || !b.valid)
return {};
472 return {a.
netdiff + b.netdiff, std::max(b.exec, b.netdiff + a.exec)};
484 static constexpr SatInfo If() noexcept {
return {1, 1}; }
490 static constexpr SatInfo OP_IFDUP(
bool nonzero)
noexcept {
return {nonzero ? -1 : 0, 0}; }
520template<
typename Key>
525 const uint32_t
k = 0;
529 const std::vector<unsigned char>
data;
531 mutable std::vector<NodeRef<Key>>
subs;
538 while (!
subs.empty()) {
541 while (!
node->subs.empty()) {
542 subs.push_back(std::move(
node->subs.back()));
543 node->subs.pop_back();
551 auto upfn = [](
const Node&
node, std::span<NodeRef<Key>> children) {
552 std::vector<NodeRef<Key>> new_subs;
553 for (
auto child = children.begin(); child != children.end(); ++child) {
554 new_subs.emplace_back(std::move(*child));
559 return TreeEval<NodeRef<Key>>(upfn);
584 :
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()) {}
589 for (
const auto& sub :
subs) {
590 subsize += sub->ScriptSize();
592 Type sub0type =
subs.size() > 0 ?
subs[0]->GetType() :
""_mst;
619 template<
typename Result,
typename State,
typename DownFn,
typename UpFn>
629 StackElem(
const Node& node_,
size_t exp_,
State&& state_) :
630 node(node_), expanded(exp_), state(std::move(state_)) {}
633 std::vector<StackElem> stack;
636 std::vector<Result> results;
637 stack.emplace_back(*
this, 0, std::move(root_state));
655 while (stack.size()) {
656 const Node&
node = stack.back().node;
657 if (stack.back().expanded <
node.subs.size()) {
661 size_t child_index = stack.back().expanded++;
662 State child_state = downfn(stack.back().state,
node, child_index);
663 stack.emplace_back(*
node.subs[child_index], 0, std::move(child_state));
668 std::optional<Result> result{upfn(std::move(stack.back().state),
node,
669 std::span<Result>{results}.last(
node.subs.size()))};
671 if (!result)
return {};
673 results.erase(results.end() -
node.subs.size(), results.end());
674 results.push_back(std::move(*result));
678 assert(results.size() >= 1);
680 return std::move(results[0]);
685 template<
typename Result,
typename UpFn>
688 struct DummyState {};
689 return TreeEvalMaybe<Result>(DummyState{},
690 [](DummyState,
const Node&, size_t) {
return DummyState{}; },
691 [&upfn](DummyState,
const Node&
node, std::span<Result>
subs) {
698 template<
typename Result,
typename State,
typename DownFn,
typename UpFn>
703 return std::move(*TreeEvalMaybe<Result>(std::move(root_state),
704 std::forward<DownFn>(downfn),
707 return std::optional<Result>(std::move(res));
714 template<
typename Result,
typename UpFn>
717 struct DummyState {};
718 return std::move(*TreeEvalMaybe<Result>(DummyState{},
719 [](DummyState,
const Node&, size_t) {
return DummyState{}; },
720 [&upfn](DummyState,
const Node&
node, std::span<Result>
subs) {
722 return std::optional<Result>(std::move(res));
730 std::vector<std::pair<const Node<Key>&,
const Node<Key>&>> queue;
731 queue.emplace_back(node1, node2);
732 while (!queue.empty()) {
733 const auto& [a, b] = queue.back();
735 if (std::tie(a.fragment, a.k, a.keys, a.data) < std::tie(b.fragment, b.k, b.keys, b.data))
return -1;
736 if (std::tie(b.fragment, b.k, b.keys, b.data) < std::tie(a.fragment, a.k, a.keys, a.data))
return 1;
737 if (a.subs.size() < b.subs.size())
return -1;
738 if (b.subs.size() < a.subs.size())
return 1;
739 size_t n = a.
subs.size();
740 for (
size_t i = 0; i < n; ++i) {
741 queue.emplace_back(*a.subs[n - 1 - i], *b.subs[n - 1 - i]);
749 using namespace internal;
752 std::vector<Type> sub_types;
754 for (
const auto& sub :
subs) sub_types.push_back(sub->GetType());
765 template<
typename Ctx>
784 switch (
node.fragment) {
798 if (
node.subs[0]->GetType() <<
"x"_mst) {
801 return std::move(
subs[0]);
818 for (
const auto& key :
node.keys) {
826 for (
auto it =
node.keys.begin() + 1; it !=
node.keys.end(); ++it) {
833 for (
size_t i = 1; i <
subs.size(); ++i) {
841 return TreeEval<CScript>(
false, downfn, upfn);
844 template<
typename CTx>
845 std::optional<std::string>
ToString(
const CTx& ctx)
const {
849 auto downfn = [](bool,
const Node&
node, size_t) {
861 auto upfn = [&ctx, is_tapscript](
bool wrapped,
const Node&
node, std::span<std::string>
subs) -> std::optional<std::string> {
862 std::string
ret = wrapped ?
":" :
"";
864 switch (
node.fragment) {
870 auto key_str = ctx.ToString(
node.subs[0]->keys[0]);
871 if (!key_str)
return {};
872 return std::move(
ret) +
"pk(" + std::move(*key_str) +
")";
876 auto key_str = ctx.ToString(
node.subs[0]->keys[0]);
877 if (!key_str)
return {};
878 return std::move(
ret) +
"pkh(" + std::move(*key_str) +
")";
880 return "c" + std::move(
subs[0]);
895 switch (
node.fragment) {
897 auto key_str = ctx.ToString(
node.keys[0]);
898 if (!key_str)
return {};
899 return std::move(
ret) +
"pk_k(" + std::move(*key_str) +
")";
902 auto key_str = ctx.ToString(
node.keys[0]);
903 if (!key_str)
return {};
904 return std::move(
ret) +
"pk_h(" + std::move(*key_str) +
")";
923 return std::move(
ret) +
"andor(" + std::move(
subs[0]) +
"," + std::move(
subs[1]) +
"," + std::move(
subs[2]) +
")";
927 for (
const auto& key :
node.keys) {
928 auto key_str = ctx.ToString(key);
929 if (!key_str)
return {};
930 str +=
"," + std::move(*key_str);
932 return std::move(str) +
")";
937 for (
const auto& key :
node.keys) {
938 auto key_str = ctx.ToString(key);
939 if (!key_str)
return {};
940 str +=
"," + std::move(*key_str);
942 return std::move(str) +
")";
946 for (
auto& sub :
subs) {
947 str +=
"," + std::move(sub);
949 return std::move(str) +
")";
956 return TreeEvalMaybe<std::string>(
false, downfn, upfn);
974 const auto count{1 +
subs[0]->ops.count +
subs[1]->ops.count};
975 const auto sat{
subs[0]->ops.sat +
subs[1]->ops.sat};
976 const auto dsat{
subs[0]->ops.dsat +
subs[1]->ops.dsat};
977 return {
count, sat, dsat};
980 const auto count{1 +
subs[0]->ops.count +
subs[1]->ops.count};
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};
987 const auto sat{
subs[0]->ops.sat | (
subs[1]->ops.sat +
subs[0]->ops.dsat)};
988 const auto dsat{
subs[0]->ops.dsat +
subs[1]->ops.dsat};
989 return {
count, sat, dsat};
992 const auto count{2 +
subs[0]->ops.count +
subs[1]->ops.count};
993 const auto sat{
subs[0]->ops.sat | (
subs[1]->ops.sat +
subs[0]->ops.dsat)};
994 return {
count, sat, {}};
997 const auto count{3 +
subs[0]->ops.count +
subs[1]->ops.count};
998 const auto sat{
subs[0]->ops.sat |
subs[1]->ops.sat};
999 const auto dsat{
subs[0]->ops.dsat |
subs[1]->ops.dsat};
1000 return {
count, sat, dsat};
1003 const auto count{3 +
subs[0]->ops.count +
subs[1]->ops.count +
subs[2]->ops.count};
1005 const auto dsat{
subs[0]->ops.dsat +
subs[2]->ops.dsat};
1006 return {
count, sat, dsat};
1020 for (
const auto& sub :
subs) {
1021 count += sub->ops.count + 1;
1022 auto next_sats =
Vector(sats[0] + sub->ops.dsat);
1023 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub->ops.dsat) | (sats[j - 1] + sub->ops.sat));
1024 next_sats.push_back(sats[sats.size() - 1] + sub->ops.sat);
1025 sats = std::move(next_sats);
1028 return {
count, sats[
k], sats[0]};
1035 using namespace internal;
1051 const auto& x{subs[0]->ss};
1052 const auto& y{subs[1]->ss};
1053 const auto& z{subs[2]->ss};
1055 (x.sat + SatInfo::If() + y.sat) | (x.dsat + SatInfo::If() + z.sat),
1056 x.dsat + SatInfo::If() + z.dsat
1060 const auto& x{subs[0]->ss};
1061 const auto& y{subs[1]->ss};
1062 return {x.sat + y.sat, {}};
1065 const auto& x{subs[0]->ss};
1066 const auto& y{subs[1]->ss};
1067 return {x.sat + y.sat + SatInfo::BinaryOp(), x.dsat + y.dsat + SatInfo::BinaryOp()};
1070 const auto& x{subs[0]->ss};
1071 const auto& y{subs[1]->ss};
1073 ((x.sat + y.dsat) | (x.dsat + y.sat)) + SatInfo::BinaryOp(),
1074 x.dsat + y.dsat + SatInfo::BinaryOp()
1078 const auto& x{subs[0]->ss};
1079 const auto& y{subs[1]->ss};
1080 return {(x.sat + SatInfo::If()) | (x.dsat + SatInfo::If() + y.sat), {}};
1083 const auto& x{subs[0]->ss};
1084 const auto& y{subs[1]->ss};
1091 const auto& x{subs[0]->ss};
1092 const auto& y{subs[1]->ss};
1093 return {SatInfo::If() + (x.sat | y.sat), SatInfo::If() + (x.dsat | y.dsat)};
1122 auto sats =
Vector(SatInfo::Empty());
1123 for (
size_t i = 0; i < subs.size(); ++i) {
1126 auto add = i ? SatInfo::BinaryOp() : SatInfo::Empty();
1128 auto next_sats =
Vector(sats[0] + subs[i]->ss.dsat + add);
1130 for (
size_t j = 1; j < sats.size(); ++j) {
1131 next_sats.push_back(((sats[j] + subs[i]->ss.dsat) | (sats[j - 1] + subs[i]->ss.sat)) + add);
1134 next_sats.push_back(sats[sats.size() - 1] + subs[i]->ss.sat + add);
1136 sats = std::move(next_sats);
1151 const uint32_t pubkey_size =
IsTapscript(m_script_ctx) ? 1 + 32 : 1 + 33;
1164 const auto sat{(subs[0]->ws.sat + subs[1]->ws.sat) | (subs[0]->ws.dsat + subs[2]->ws.sat)};
1165 const auto dsat{subs[0]->ws.dsat + subs[2]->ws.dsat};
1169 case Fragment::AND_B:
return {subs[0]->ws.sat + subs[1]->ws.sat, subs[0]->ws.dsat + subs[1]->ws.dsat};
1171 const auto sat{(subs[0]->ws.dsat + subs[1]->ws.sat) | (subs[0]->ws.sat + subs[1]->ws.dsat)};
1172 const auto dsat{subs[0]->ws.dsat + subs[1]->ws.dsat};
1175 case Fragment::OR_C:
return {subs[0]->ws.sat | (subs[0]->ws.dsat + subs[1]->ws.sat), {}};
1176 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};
1177 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)};
1189 for (
const auto& sub : subs) {
1190 auto next_sats =
Vector(sats[0] + sub->ws.dsat);
1191 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub->ws.dsat) | (sats[j - 1] + sub->ws.sat));
1192 next_sats.push_back(sats[sats.size() - 1] + sub->ws.sat);
1193 sats = std::move(next_sats);
1196 return {sats[
k], sats[0]};
1202 template<
typename Ctx>
1204 using namespace internal;
1208 auto helper = [&ctx](
const Node&
node, std::span<InputResult> subres) -> InputResult {
1209 switch (
node.fragment) {
1211 std::vector<unsigned char> sig;
1213 return {
ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
1216 std::vector<unsigned char> key = ctx.ToPKBytes(
node.keys[0]), sig;
1218 return {
ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
1224 for (
size_t i = 0; i <
node.keys.size(); ++i) {
1227 std::vector<unsigned char> sig;
1230 auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1234 std::vector<InputStack> next_sats;
1235 next_sats.push_back(sats[0] +
ZERO);
1236 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] +
ZERO) | (std::move(sats[j - 1]) + sat));
1237 next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1239 sats = std::move(next_sats);
1243 auto& nsat{sats[0]};
1246 return {std::move(nsat), std::move(sats[
node.k])};
1253 for (
size_t i = 0; i <
node.keys.size(); ++i) {
1254 std::vector<unsigned char> sig;
1257 auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1261 std::vector<InputStack> next_sats;
1262 next_sats.push_back(sats[0]);
1263 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
1264 next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1266 sats = std::move(next_sats);
1269 InputStack nsat =
ZERO;
1270 for (
size_t i = 0; i <
node.k; ++i) nsat = std::move(nsat) +
ZERO;
1272 return {std::move(nsat), std::move(sats[
node.k])};
1279 for (
size_t i = 0; i < subres.size(); ++i) {
1281 auto& res = subres[subres.size() - i - 1];
1285 std::vector<InputStack> next_sats;
1286 next_sats.push_back(sats[0] + res.nsat);
1287 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + res.nsat) | (std::move(sats[j - 1]) + res.sat));
1288 next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
1290 sats = std::move(next_sats);
1294 InputStack nsat = INVALID;
1295 for (
size_t i = 0; i < sats.size(); ++i) {
1302 if (i != 0 && i !=
node.k) sats[i].SetMalleable().SetNonCanon();
1304 if (i !=
node.k) nsat = std::move(nsat) | std::move(sats[i]);
1307 return {std::move(nsat), std::move(sats[
node.k])};
1310 return {INVALID, ctx.CheckOlder(
node.k) ?
EMPTY : INVALID};
1313 return {INVALID, ctx.CheckAfter(
node.k) ?
EMPTY : INVALID};
1316 std::vector<unsigned char> preimage;
1318 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1321 std::vector<unsigned char> preimage;
1323 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1326 std::vector<unsigned char> preimage;
1328 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1331 std::vector<unsigned char> preimage;
1333 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1336 auto& x = subres[0], &y = subres[1];
1343 return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
1346 auto& x = subres[0], &y = subres[1];
1352 return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
1355 auto& x = subres[0], &z = subres[1];
1357 return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
1360 auto& x = subres[0], &z = subres[1];
1361 return {INVALID, std::move(x.sat) | (z.sat + x.nsat)};
1364 auto& x = subres[0], &z = subres[1];
1365 return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
1368 auto& x = subres[0], &z = subres[1];
1369 return {(x.nsat + ONE) | (z.nsat +
ZERO), (x.sat + ONE) | (z.sat +
ZERO)};
1372 auto& x = subres[0], &y = subres[1], &z = subres[2];
1373 return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
1379 return std::move(subres[0]);
1381 auto &x = subres[0];
1382 return {
ZERO, x.sat + ONE};
1385 auto &x = subres[0];
1391 return {InputStack(
ZERO).SetMalleable(x.nsat.available !=
Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
1394 auto &x = subres[0];
1395 return {INVALID, std::move(x.sat)};
1401 return {INVALID, INVALID};
1404 auto tester = [&helper](
const Node&
node, std::span<InputResult> subres) -> InputResult {
1405 auto ret = helper(
node, subres);
1447 return TreeEval<InputResult>(tester);
1462 Comp(
const Ctx& ctx) : ctx_ptr(&ctx) {}
1463 bool operator()(
const Key& a,
const Key& b)
const {
return ctx_ptr->KeyCompare(a, b); }
1469 using keyset = std::set<Key, Comp>;
1470 using state = std::optional<keyset>;
1472 auto upfn = [&ctx](
const Node&
node, std::span<state> subs) -> state {
1474 if (
node.has_duplicate_keys.has_value() && *
node.has_duplicate_keys)
return {};
1477 for (
auto& sub : subs) {
1478 if (!sub.has_value()) {
1479 node.has_duplicate_keys =
true;
1486 size_t keys_count =
node.keys.size();
1487 keyset key_set{
node.keys.begin(),
node.keys.end(), Comp(ctx)};
1488 if (key_set.size() != keys_count) {
1490 node.has_duplicate_keys =
true;
1495 for (
auto& sub : subs) {
1496 keys_count += sub->size();
1499 if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1500 key_set.merge(*sub);
1501 if (key_set.size() != keys_count) {
1502 node.has_duplicate_keys =
true;
1507 node.has_duplicate_keys =
false;
1511 TreeEval<state>(upfn);
1519 if (!ops.sat.valid)
return {};
1520 return ops.count + ops.sat.value;
1535 return !((GetType() &
"BKW"_mst) ==
""_mst);
1540 if (!ss.sat.valid)
return {};
1541 return ss.sat.netdiff +
static_cast<int32_t
>(IsBKW());
1546 if (!ss.sat.valid)
return {};
1547 return ss.sat.exec +
static_cast<int32_t
>(IsBKW());
1555 if (
const auto exec_ss = GetExecStackSize())
return exec_ss <=
MAX_STACK_SIZE;
1568 if (!ws.sat.valid)
return {};
1569 return ws.sat.value;
1580 return TreeEval<const Node*>([](
const Node&
node, std::span<const Node*> subs) ->
const Node* {
1581 for (
auto& sub: subs)
if (sub)
return sub;
1582 if (!
node.IsSaneSubexpression())
return &
node;
1589 template<
typename F>
1593 return TreeEval<int>([&fn](
const Node&
node, std::span<int> subs) ->
bool {
1594 switch (
node.fragment) {
1595 case Fragment::JUST_0:
1597 case Fragment::JUST_1:
1599 case Fragment::PK_K:
1600 case Fragment::PK_H:
1601 case Fragment::MULTI:
1602 case Fragment::MULTI_A:
1603 case Fragment::AFTER:
1604 case Fragment::OLDER:
1605 case Fragment::HASH256:
1606 case Fragment::HASH160:
1607 case Fragment::SHA256:
1608 case Fragment::RIPEMD160:
1609 return bool{fn(node)};
1611 return (subs[0] && subs[1]) || subs[2];
1614 return subs[0] && subs[1];
1619 return subs[0] || subs[1];
1621 return static_cast<uint32_t
>(
std::count(subs.begin(), subs.end(),
true)) >=
node.k;
1623 assert(subs.size() >= 1);
1632 if (GetType() ==
""_mst)
return false;
1655 bool IsSaneSubexpression()
const {
return ValidSatisfactions() && IsNonMalleable() && CheckTimeLocksMix() && CheckDuplicateKey(); }
1658 bool IsSane()
const {
return IsValidTopLevel() && IsSaneSubexpression() && NeedsSignature(); }
1664 template<
typename Ctx>
1665 Availability Satisfy(
const Ctx& ctx, std::vector<std::vector<unsigned char>>& stack,
bool nonmalleable =
true)
const {
1666 auto ret = ProduceInput(ctx);
1667 if (nonmalleable && (
ret.sat.malleable || !
ret.sat.has_sig))
return Availability::NO;
1668 stack = std::move(
ret.sat.stack);
1669 return ret.sat.available;
1677 : 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()) {}
1679 : fragment(nt),
k(val),
data(
std::move(arg)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1681 : 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()) {}
1683 : fragment(nt),
k(val), keys(
std::move(key)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1685 : fragment(nt),
k(val), subs(
std::move(sub)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1687 : fragment(nt),
k(val), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1690 template <
typename Ctx>
Node(
const Ctx& ctx,
Fragment nt, std::vector<
NodeRef<Key>> sub, std::vector<unsigned char> arg, uint32_t val = 0)
1691 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(sub),
std::move(arg), val) { DuplicateKeyCheck(ctx); }
1692 template <
typename Ctx>
Node(
const Ctx& ctx,
Fragment nt, std::vector<unsigned char> arg, uint32_t val = 0)
1693 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(arg), val) { DuplicateKeyCheck(ctx);}
1695 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(sub),
std::move(key), val) { DuplicateKeyCheck(ctx); }
1696 template <
typename Ctx>
Node(
const Ctx& ctx,
Fragment nt, std::vector<Key> key, uint32_t val = 0)
1697 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(key), val) { DuplicateKeyCheck(ctx); }
1699 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(sub), val) { DuplicateKeyCheck(ctx); }
1700 template <
typename Ctx>
Node(
const Ctx& ctx,
Fragment nt, uint32_t val = 0)
1701 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt, val) { DuplicateKeyCheck(ctx); }
1767template<
typename Key,
typename Ctx>
1768std::optional<std::pair<Key, int>>
ParseKeyEnd(std::span<const char> in,
const Ctx& ctx)
1771 if (key_size < 1)
return {};
1772 auto key = ctx.FromString(in.begin(), in.begin() + key_size);
1773 if (!key)
return {};
1774 return {{std::move(*key), key_size}};
1778template<
typename Ctx>
1779std::optional<std::pair<std::vector<unsigned char>,
int>>
ParseHexStrEnd(std::span<const char> in,
const size_t expected_size,
1783 if (hash_size < 1)
return {};
1784 std::string val = std::string(in.begin(), in.begin() + hash_size);
1785 if (!
IsHex(val))
return {};
1787 if (hash.size() != expected_size)
return {};
1788 return {{std::move(hash), hash_size}};
1792template<
typename Key>
1796 constructed.pop_back();
1798 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, script_ctx, nt,
Vector(std::move(child), std::move(constructed.back())));
1800 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, script_ctx, nt,
Vector(std::move(constructed.back()), std::move(child)));
1809template<
typename Key,
typename Ctx>
1824 size_t script_size{1};
1828 std::vector<std::tuple<ParseContext, int64_t, int64_t>> to_parse;
1829 std::vector<NodeRef<Key>> constructed;
1831 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
1834 const auto parse_multi_exp = [&](std::span<const char>& in,
const bool is_multi_a) ->
bool {
1836 const auto required_ctx{is_multi_a ? MiniscriptContext::TAPSCRIPT : MiniscriptContext::P2WSH};
1837 if (ctx.MsContext() != required_ctx)
return false;
1840 if (next_comma < 1)
return false;
1841 const auto k_to_integral{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
1842 if (!k_to_integral.has_value())
return false;
1843 const int64_t
k{k_to_integral.value()};
1844 in = in.subspan(next_comma + 1);
1846 std::vector<Key> keys;
1847 while (next_comma != -1) {
1849 int key_length = (next_comma == -1) ?
FindNextChar(in,
')') : next_comma;
1850 if (key_length < 1)
return false;
1851 auto key = ctx.FromString(in.begin(), in.begin() + key_length);
1852 if (!key)
return false;
1853 keys.push_back(std::move(*key));
1854 in = in.subspan(key_length + 1);
1856 if (keys.size() < 1 || keys.size() > max_keys)
return false;
1857 if (k < 1 || k > (int64_t)keys.size())
return false;
1861 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys),
k));
1863 script_size += 2 + (keys.size() > 16) + (
k > 16) + 34 * keys.size();
1864 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys),
k));
1869 while (!to_parse.empty()) {
1870 if (script_size > max_size)
return {};
1873 auto [cur_context, n,
k] = to_parse.back();
1874 to_parse.pop_back();
1876 switch (cur_context) {
1877 case ParseContext::WRAPPED_EXPR: {
1878 std::optional<size_t> colon_index{};
1879 for (
size_t i = 1; i < in.size(); ++i) {
1884 if (in[i] <
'a' || in[i] >
'z')
break;
1887 bool last_was_v{
false};
1888 for (
size_t j = 0; colon_index && j < *colon_index; ++j) {
1889 if (script_size > max_size)
return {};
1892 to_parse.emplace_back(ParseContext::ALT, -1, -1);
1893 }
else if (in[j] ==
's') {
1895 to_parse.emplace_back(ParseContext::SWAP, -1, -1);
1896 }
else if (in[j] ==
'c') {
1899 }
else if (in[j] ==
'd') {
1901 to_parse.emplace_back(ParseContext::DUP_IF, -1, -1);
1902 }
else if (in[j] ==
'j') {
1904 to_parse.emplace_back(ParseContext::NON_ZERO, -1, -1);
1905 }
else if (in[j] ==
'n') {
1907 to_parse.emplace_back(ParseContext::ZERO_NOTEQUAL, -1, -1);
1908 }
else if (in[j] ==
'v') {
1911 if (last_was_v)
return {};
1912 to_parse.emplace_back(ParseContext::VERIFY, -1, -1);
1913 }
else if (in[j] ==
'u') {
1915 to_parse.emplace_back(ParseContext::WRAP_U, -1, -1);
1916 }
else if (in[j] ==
't') {
1918 to_parse.emplace_back(ParseContext::WRAP_T, -1, -1);
1919 }
else if (in[j] ==
'l') {
1922 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0));
1923 to_parse.emplace_back(ParseContext::OR_I, -1, -1);
1927 last_was_v = (in[j] ==
'v');
1929 to_parse.emplace_back(ParseContext::EXPR, -1, -1);
1930 if (colon_index) in = in.subspan(*colon_index + 1);
1933 case ParseContext::EXPR: {
1934 if (
Const(
"0", in)) {
1935 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0));
1936 }
else if (
Const(
"1", in)) {
1937 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1));
1938 }
else if (
Const(
"pk(", in)) {
1939 auto res = ParseKeyEnd<Key, Ctx>(in, ctx);
1940 if (!res)
return {};
1941 auto& [key, key_size] = *res;
1943 in = in.subspan(key_size + 1);
1944 script_size +=
IsTapscript(ctx.MsContext()) ? 33 : 34;
1945 }
else if (
Const(
"pkh(", in)) {
1946 auto res = ParseKeyEnd<Key>(in, ctx);
1947 if (!res)
return {};
1948 auto& [key, key_size] = *res;
1950 in = in.subspan(key_size + 1);
1952 }
else if (
Const(
"pk_k(", in)) {
1953 auto res = ParseKeyEnd<Key>(in, ctx);
1954 if (!res)
return {};
1955 auto& [key, key_size] = *res;
1957 in = in.subspan(key_size + 1);
1958 script_size +=
IsTapscript(ctx.MsContext()) ? 32 : 33;
1959 }
else if (
Const(
"pk_h(", in)) {
1960 auto res = ParseKeyEnd<Key>(in, ctx);
1961 if (!res)
return {};
1962 auto& [key, key_size] = *res;
1964 in = in.subspan(key_size + 1);
1966 }
else if (
Const(
"sha256(", in)) {
1968 if (!res)
return {};
1969 auto& [hash, hash_size] = *res;
1970 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, std::move(hash)));
1971 in = in.subspan(hash_size + 1);
1973 }
else if (
Const(
"ripemd160(", in)) {
1975 if (!res)
return {};
1976 auto& [hash, hash_size] = *res;
1978 in = in.subspan(hash_size + 1);
1980 }
else if (
Const(
"hash256(", in)) {
1982 if (!res)
return {};
1983 auto& [hash, hash_size] = *res;
1984 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, std::move(hash)));
1985 in = in.subspan(hash_size + 1);
1987 }
else if (
Const(
"hash160(", in)) {
1989 if (!res)
return {};
1990 auto& [hash, hash_size] = *res;
1991 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, std::move(hash)));
1992 in = in.subspan(hash_size + 1);
1994 }
else if (
Const(
"after(", in)) {
1996 if (arg_size < 1)
return {};
1997 const auto num{ToIntegral<int64_t>(std::string_view(in.data(), arg_size))};
1998 if (!num.has_value() || *num < 1 || *num >= 0x80000000L)
return {};
1999 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num));
2000 in = in.subspan(arg_size + 1);
2001 script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
2002 }
else if (
Const(
"older(", in)) {
2004 if (arg_size < 1)
return {};
2005 const auto num{ToIntegral<int64_t>(std::string_view(in.data(), arg_size))};
2006 if (!num.has_value() || *num < 1 || *num >= 0x80000000L)
return {};
2007 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num));
2008 in = in.subspan(arg_size + 1);
2009 script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
2010 }
else if (
Const(
"multi(", in)) {
2011 if (!parse_multi_exp(in,
false))
return {};
2012 }
else if (
Const(
"multi_a(", in)) {
2013 if (!parse_multi_exp(in,
true))
return {};
2014 }
else if (
Const(
"thresh(", in)) {
2016 if (next_comma < 1)
return {};
2017 const auto k{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
2018 if (!
k.has_value() || *
k < 1)
return {};
2019 in = in.subspan(next_comma + 1);
2021 to_parse.emplace_back(ParseContext::THRESH, 1, *
k);
2022 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2023 script_size += 2 + (*
k > 16) + (*
k > 0x7f) + (*
k > 0x7fff) + (*
k > 0x7fffff);
2024 }
else if (
Const(
"andor(", in)) {
2025 to_parse.emplace_back(ParseContext::ANDOR, -1, -1);
2026 to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
2027 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2028 to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2029 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2030 to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2031 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2034 if (
Const(
"and_n(", in)) {
2035 to_parse.emplace_back(ParseContext::AND_N, -1, -1);
2037 }
else if (
Const(
"and_b(", in)) {
2038 to_parse.emplace_back(ParseContext::AND_B, -1, -1);
2040 }
else if (
Const(
"and_v(", in)) {
2041 to_parse.emplace_back(ParseContext::AND_V, -1, -1);
2043 }
else if (
Const(
"or_b(", in)) {
2044 to_parse.emplace_back(ParseContext::OR_B, -1, -1);
2046 }
else if (
Const(
"or_c(", in)) {
2047 to_parse.emplace_back(ParseContext::OR_C, -1, -1);
2049 }
else if (
Const(
"or_d(", in)) {
2050 to_parse.emplace_back(ParseContext::OR_D, -1, -1);
2052 }
else if (
Const(
"or_i(", in)) {
2053 to_parse.emplace_back(ParseContext::OR_I, -1, -1);
2058 to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
2059 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2060 to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2061 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2065 case ParseContext::ALT: {
2066 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A,
Vector(std::move(constructed.back())));
2069 case ParseContext::SWAP: {
2070 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S,
Vector(std::move(constructed.back())));
2074 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C,
Vector(std::move(constructed.back())));
2077 case ParseContext::DUP_IF: {
2078 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D,
Vector(std::move(constructed.back())));
2081 case ParseContext::NON_ZERO: {
2082 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J,
Vector(std::move(constructed.back())));
2085 case ParseContext::ZERO_NOTEQUAL: {
2086 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N,
Vector(std::move(constructed.back())));
2089 case ParseContext::VERIFY: {
2090 script_size += (constructed.back()->GetType() <<
"x"_mst);
2091 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V,
Vector(std::move(constructed.back())));
2094 case ParseContext::WRAP_U: {
2098 case ParseContext::WRAP_T: {
2102 case ParseContext::AND_B: {
2103 BuildBack(ctx.MsContext(), Fragment::AND_B, constructed);
2106 case ParseContext::AND_N: {
2107 auto mid = std::move(constructed.back());
2108 constructed.pop_back();
2109 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)));
2112 case ParseContext::AND_V: {
2113 BuildBack(ctx.MsContext(), Fragment::AND_V, constructed);
2116 case ParseContext::OR_B: {
2117 BuildBack(ctx.MsContext(), Fragment::OR_B, constructed);
2120 case ParseContext::OR_C: {
2121 BuildBack(ctx.MsContext(), Fragment::OR_C, constructed);
2124 case ParseContext::OR_D: {
2125 BuildBack(ctx.MsContext(), Fragment::OR_D, constructed);
2128 case ParseContext::OR_I: {
2129 BuildBack(ctx.MsContext(), Fragment::OR_I, constructed);
2132 case ParseContext::ANDOR: {
2133 auto right = std::move(constructed.back());
2134 constructed.pop_back();
2135 auto mid = std::move(constructed.back());
2136 constructed.pop_back();
2137 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR,
Vector(std::move(constructed.back()), std::move(mid), std::move(right)));
2140 case ParseContext::THRESH: {
2141 if (in.size() < 1)
return {};
2144 to_parse.emplace_back(ParseContext::THRESH, n+1,
k);
2145 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2147 }
else if (in[0] ==
')') {
2148 if (
k > n)
return {};
2151 std::vector<NodeRef<Key>> subs;
2152 for (
int i = 0; i < n; ++i) {
2153 subs.push_back(std::move(constructed.back()));
2154 constructed.pop_back();
2156 std::reverse(subs.begin(), subs.end());
2157 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs),
k));
2163 case ParseContext::COMMA: {
2164 if (in.size() < 1 || in[0] !=
',')
return {};
2168 case ParseContext::CLOSE_BRACKET: {
2169 if (in.size() < 1 || in[0] !=
')')
return {};
2177 assert(constructed.size() >= 1);
2179 assert(constructed[0]->ScriptSize() == script_size);
2180 if (in.size() > 0)
return {};
2182 tl_node->DuplicateKeyCheck(ctx);
2268template<
typename Key,
typename Ctx,
typename I>
2272 std::vector<std::tuple<DecodeContext, int64_t, int64_t>> to_parse;
2273 std::vector<NodeRef<Key>> constructed;
2277 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2279 while (!to_parse.empty()) {
2281 if (!constructed.empty() && !constructed.back()->IsValid())
return {};
2284 auto [cur_context, n,
k] = to_parse.back();
2285 to_parse.pop_back();
2287 switch(cur_context) {
2288 case DecodeContext::SINGLE_BKV_EXPR: {
2289 if (in >= last)
return {};
2292 if (in[0].first ==
OP_1) {
2294 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1));
2297 if (in[0].first ==
OP_0) {
2299 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0));
2303 if (in[0].second.size() == 33 || in[0].second.size() == 32) {
2304 auto key = ctx.FromPKBytes(in[0].second.begin(), in[0].second.end());
2305 if (!key)
return {};
2311 auto key = ctx.FromPKHBytes(in[2].second.begin(), in[2].second.end());
2312 if (!key)
return {};
2318 std::optional<int64_t> num;
2321 if (*num < 1 || *num > 0x7FFFFFFFL)
return {};
2322 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num));
2327 if (num < 1 || num > 0x7FFFFFFFL)
return {};
2328 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num));
2333 if (in[2].first ==
OP_SHA256 && in[1].second.size() == 32) {
2334 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, in[1].second));
2337 }
else if (in[2].first ==
OP_RIPEMD160 && in[1].second.size() == 20) {
2341 }
else if (in[2].first ==
OP_HASH256 && in[1].second.size() == 32) {
2342 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, in[1].second));
2345 }
else if (in[2].first ==
OP_HASH160 && in[1].second.size() == 20) {
2346 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, in[1].second));
2354 std::vector<Key> keys;
2356 if (!n || last - in < 3 + *n)
return {};
2357 if (*n < 1 || *n > 20)
return {};
2358 for (
int i = 0; i < *n; ++i) {
2359 if (in[2 + i].second.size() != 33)
return {};
2360 auto key = ctx.FromPKBytes(in[2 + i].second.begin(), in[2 + i].second.end());
2361 if (!key)
return {};
2362 keys.push_back(std::move(*key));
2365 if (!
k || *k < 1 || *k > *n)
return {};
2367 std::reverse(keys.begin(), keys.end());
2368 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), *
k));
2372 if (last - in >= 4 && in[0].first ==
OP_NUMEQUAL) {
2378 if (last - in < 2 + *
k * 2)
return {};
2379 std::vector<Key> keys;
2382 for (
int pos = 2;; pos += 2) {
2383 if (last - in < pos + 2)
return {};
2386 if (in[pos + 1].second.size() != 32)
return {};
2387 auto key = ctx.FromPKBytes(in[pos + 1].second.begin(), in[pos + 1].second.end());
2388 if (!key)
return {};
2389 keys.push_back(std::move(*key));
2395 if (keys.size() < (
size_t)*
k)
return {};
2396 in += 2 + keys.size() * 2;
2397 std::reverse(keys.begin(), keys.end());
2398 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), *
k));
2408 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2414 to_parse.emplace_back(DecodeContext::VERIFY, -1, -1);
2415 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2421 to_parse.emplace_back(DecodeContext::ZERO_NOTEQUAL, -1, -1);
2422 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2427 if (*num < 1)
return {};
2429 to_parse.emplace_back(DecodeContext::THRESH_W, 0, *num);
2435 to_parse.emplace_back(DecodeContext::ENDIF, -1, -1);
2436 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2447 to_parse.emplace_back(DecodeContext::AND_B, -1, -1);
2448 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2449 to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2455 to_parse.emplace_back(DecodeContext::OR_B, -1, -1);
2456 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2457 to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2463 case DecodeContext::BKV_EXPR: {
2464 to_parse.emplace_back(DecodeContext::MAYBE_AND_V, -1, -1);
2465 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2468 case DecodeContext::W_EXPR: {
2470 if (in >= last)
return {};
2473 to_parse.emplace_back(DecodeContext::ALT, -1, -1);
2475 to_parse.emplace_back(DecodeContext::SWAP, -1, -1);
2477 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2480 case DecodeContext::MAYBE_AND_V: {
2484 to_parse.emplace_back(DecodeContext::AND_V, -1, -1);
2486 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2490 case DecodeContext::SWAP: {
2491 if (in >= last || in[0].first !=
OP_SWAP || constructed.empty())
return {};
2493 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S,
Vector(std::move(constructed.back())));
2496 case DecodeContext::ALT: {
2497 if (in >= last || in[0].first !=
OP_TOALTSTACK || constructed.empty())
return {};
2499 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A,
Vector(std::move(constructed.back())));
2503 if (constructed.empty())
return {};
2504 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C,
Vector(std::move(constructed.back())));
2507 case DecodeContext::DUP_IF: {
2508 if (constructed.empty())
return {};
2509 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D,
Vector(std::move(constructed.back())));
2512 case DecodeContext::VERIFY: {
2513 if (constructed.empty())
return {};
2514 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V,
Vector(std::move(constructed.back())));
2517 case DecodeContext::NON_ZERO: {
2518 if (constructed.empty())
return {};
2519 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J,
Vector(std::move(constructed.back())));
2522 case DecodeContext::ZERO_NOTEQUAL: {
2523 if (constructed.empty())
return {};
2524 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N,
Vector(std::move(constructed.back())));
2527 case DecodeContext::AND_V: {
2528 if (constructed.size() < 2)
return {};
2529 BuildBack(ctx.MsContext(), Fragment::AND_V, constructed,
true);
2532 case DecodeContext::AND_B: {
2533 if (constructed.size() < 2)
return {};
2534 BuildBack(ctx.MsContext(), Fragment::AND_B, constructed,
true);
2537 case DecodeContext::OR_B: {
2538 if (constructed.size() < 2)
return {};
2539 BuildBack(ctx.MsContext(), Fragment::OR_B, constructed,
true);
2542 case DecodeContext::OR_C: {
2543 if (constructed.size() < 2)
return {};
2544 BuildBack(ctx.MsContext(), Fragment::OR_C, constructed,
true);
2547 case DecodeContext::OR_D: {
2548 if (constructed.size() < 2)
return {};
2549 BuildBack(ctx.MsContext(), Fragment::OR_D, constructed,
true);
2552 case DecodeContext::ANDOR: {
2553 if (constructed.size() < 3)
return {};
2555 constructed.pop_back();
2557 constructed.pop_back();
2559 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR,
Vector(std::move(left), std::move(mid), std::move(right)));
2562 case DecodeContext::THRESH_W: {
2563 if (in >= last)
return {};
2564 if (in[0].first ==
OP_ADD) {
2566 to_parse.emplace_back(DecodeContext::THRESH_W, n+1,
k);
2567 to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2569 to_parse.emplace_back(DecodeContext::THRESH_E, n+1,
k);
2571 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2575 case DecodeContext::THRESH_E: {
2576 if (k < 1 || k > n || constructed.size() <
static_cast<size_t>(n))
return {};
2577 std::vector<NodeRef<Key>> subs;
2578 for (
int i = 0; i < n; ++i) {
2580 constructed.pop_back();
2581 subs.push_back(std::move(sub));
2583 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs),
k));
2586 case DecodeContext::ENDIF: {
2587 if (in >= last)
return {};
2592 to_parse.emplace_back(DecodeContext::ENDIF_ELSE, -1, -1);
2593 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2596 else if (in[0].first ==
OP_IF) {
2597 if (last - in >= 2 && in[1].first ==
OP_DUP) {
2599 to_parse.emplace_back(DecodeContext::DUP_IF, -1, -1);
2602 to_parse.emplace_back(DecodeContext::NON_ZERO, -1, -1);
2608 }
else if (in[0].first ==
OP_NOTIF) {
2610 to_parse.emplace_back(DecodeContext::ENDIF_NOTIF, -1, -1);
2617 case DecodeContext::ENDIF_NOTIF: {
2618 if (in >= last)
return {};
2621 to_parse.emplace_back(DecodeContext::OR_D, -1, -1);
2623 to_parse.emplace_back(DecodeContext::OR_C, -1, -1);
2626 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2629 case DecodeContext::ENDIF_ELSE: {
2630 if (in >= last)
return {};
2631 if (in[0].first ==
OP_IF) {
2633 BuildBack(ctx.MsContext(), Fragment::OR_I, constructed,
true);
2634 }
else if (in[0].first ==
OP_NOTIF) {
2636 to_parse.emplace_back(DecodeContext::ANDOR, -1, -1);
2638 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2646 if (constructed.size() != 1)
return {};
2648 tl_node->DuplicateKeyCheck(ctx);
2651 if (!tl_node->IsValidTopLevel())
return {};
2657template<
typename Ctx>
2659 return internal::Parse<typename Ctx::Key>(str, ctx);
2662template<
typename Ctx>
2664 using namespace internal;
2668 if (!decomposed)
return {};
2669 auto it = decomposed->begin();
2670 auto ret = DecodeScript<typename Ctx::Key>(it, decomposed->end(), ctx);
2671 if (!
ret)
return {};
2672 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.
void ForEachNode(const Node< Key > &root, Fn &&fn)
Unordered traversal of a miniscript node tree.
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.