5#ifndef BITCOIN_SCRIPT_MINISCRIPT_H
6#define BITCOIN_SCRIPT_MINISCRIPT_H
157inline consteval Type operator""_mst(
const char* c,
size_t l)
161 for (
const char *p = c; p < c + l; p++) {
173 *p ==
'f' ? 1 << 10 :
174 *p ==
's' ? 1 << 11 :
175 *p ==
'm' ? 1 << 12 :
176 *p ==
'x' ? 1 << 13 :
177 *p ==
'g' ? 1 << 14 :
178 *p ==
'h' ? 1 << 15 :
179 *p ==
'i' ? 1 << 16 :
180 *p ==
'j' ? 1 << 17 :
181 *p ==
'k' ? 1 << 18 :
182 (
throw std::logic_error(
"Unknown character in _mst literal"), 0)
189using Opcode = std::pair<opcodetype, std::vector<unsigned char>>;
191template<
typename Key>
struct Node;
192template<
typename Key>
using NodeRef = std::shared_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();
553 for (
const auto& sub :
subs) {
554 subsize += sub->ScriptSize();
556 static constexpr auto NONE_MST{
""_mst};
557 Type sub0type =
subs.size() > 0 ?
subs[0]->GetType() : NONE_MST;
584 template<
typename Result,
typename State,
typename DownFn,
typename UpFn>
585 std::optional<Result>
TreeEvalMaybe(State root_state, DownFn downfn, UpFn upfn)
const
594 StackElem(
const Node& node_,
size_t exp_, State&& state_) :
595 node(node_), expanded(exp_), state(std::move(state_)) {}
598 std::vector<StackElem> stack;
601 std::vector<Result> results;
602 stack.emplace_back(*
this, 0, std::move(root_state));
620 while (stack.size()) {
621 const Node&
node = stack.back().node;
622 if (stack.back().expanded <
node.subs.size()) {
626 size_t child_index = stack.back().expanded++;
627 State child_state = downfn(stack.back().state,
node, child_index);
628 stack.emplace_back(*
node.subs[child_index], 0, std::move(child_state));
633 std::optional<Result> result{upfn(std::move(stack.back().state),
node,
636 if (!result)
return {};
638 results.erase(results.end() -
node.subs.size(), results.end());
639 results.push_back(std::move(*result));
643 assert(results.size() == 1);
644 return std::move(results[0]);
649 template<
typename Result,
typename UpFn>
652 struct DummyState {};
653 return TreeEvalMaybe<Result>(DummyState{},
654 [](DummyState,
const Node&, size_t) {
return DummyState{}; },
662 template<
typename Result,
typename State,
typename DownFn,
typename UpFn>
667 return std::move(*TreeEvalMaybe<Result>(std::move(root_state),
668 std::forward<DownFn>(downfn),
671 return std::optional<Result>(std::move(res));
678 template<
typename Result,
typename UpFn>
681 struct DummyState {};
682 return std::move(*TreeEvalMaybe<Result>(DummyState{},
683 [](DummyState,
const Node&, size_t) {
return DummyState{}; },
686 return std::optional<Result>(std::move(res));
694 std::vector<std::pair<const Node<Key>&,
const Node<Key>&>> queue;
695 queue.emplace_back(node1, node2);
696 while (!queue.empty()) {
697 const auto& [a, b] = queue.back();
699 if (std::tie(a.fragment, a.k, a.keys, a.data) < std::tie(b.fragment, b.k, b.keys, b.data))
return -1;
700 if (std::tie(b.fragment, b.k, b.keys, b.data) < std::tie(a.fragment, a.k, a.keys, a.data))
return 1;
701 if (a.subs.size() < b.subs.size())
return -1;
702 if (b.subs.size() < a.subs.size())
return 1;
703 size_t n = a.
subs.size();
704 for (
size_t i = 0; i < n; ++i) {
705 queue.emplace_back(*a.subs[n - 1 - i], *b.subs[n - 1 - i]);
713 using namespace internal;
716 std::vector<Type> sub_types;
718 for (
const auto& sub :
subs) sub_types.push_back(sub->GetType());
721 static constexpr auto NONE_MST{
""_mst};
722 Type x =
subs.size() > 0 ?
subs[0]->GetType() : NONE_MST;
723 Type y =
subs.size() > 1 ?
subs[1]->GetType() : NONE_MST;
724 Type z =
subs.size() > 2 ?
subs[2]->GetType() : NONE_MST;
730 template<
typename Ctx>
749 switch (
node.fragment) {
763 if (
node.subs[0]->GetType() <<
"x"_mst) {
766 return std::move(
subs[0]);
783 for (
const auto& key :
node.keys) {
791 for (
auto it =
node.keys.begin() + 1; it !=
node.keys.end(); ++it) {
798 for (
size_t i = 1; i <
subs.size(); ++i) {
806 return TreeEval<CScript>(
false, downfn, upfn);
809 template<
typename CTx>
810 std::optional<std::string>
ToString(
const CTx& ctx)
const {
814 auto downfn = [](bool,
const Node&
node, size_t) {
827 std::string
ret = wrapped ?
":" :
"";
829 switch (
node.fragment) {
835 auto key_str = ctx.ToString(
node.subs[0]->keys[0]);
836 if (!key_str)
return {};
837 return std::move(
ret) +
"pk(" + std::move(*key_str) +
")";
841 auto key_str = ctx.ToString(
node.subs[0]->keys[0]);
842 if (!key_str)
return {};
843 return std::move(
ret) +
"pkh(" + std::move(*key_str) +
")";
845 return "c" + std::move(
subs[0]);
860 switch (
node.fragment) {
862 auto key_str = ctx.ToString(
node.keys[0]);
863 if (!key_str)
return {};
864 return std::move(
ret) +
"pk_k(" + std::move(*key_str) +
")";
867 auto key_str = ctx.ToString(
node.keys[0]);
868 if (!key_str)
return {};
869 return std::move(
ret) +
"pk_h(" + std::move(*key_str) +
")";
888 return std::move(
ret) +
"andor(" + std::move(
subs[0]) +
"," + std::move(
subs[1]) +
"," + std::move(
subs[2]) +
")";
892 for (
const auto& key :
node.keys) {
893 auto key_str = ctx.ToString(key);
894 if (!key_str)
return {};
895 str +=
"," + std::move(*key_str);
897 return std::move(str) +
")";
902 for (
const auto& key :
node.keys) {
903 auto key_str = ctx.ToString(key);
904 if (!key_str)
return {};
905 str +=
"," + std::move(*key_str);
907 return std::move(str) +
")";
911 for (
auto& sub :
subs) {
912 str +=
"," + std::move(sub);
914 return std::move(str) +
")";
921 return TreeEvalMaybe<std::string>(
false, downfn, upfn);
939 const auto count{1 +
subs[0]->ops.count +
subs[1]->ops.count};
940 const auto sat{
subs[0]->ops.sat +
subs[1]->ops.sat};
941 const auto dsat{
subs[0]->ops.dsat +
subs[1]->ops.dsat};
942 return {
count, sat, dsat};
945 const auto count{1 +
subs[0]->ops.count +
subs[1]->ops.count};
947 const auto dsat{
subs[0]->ops.dsat +
subs[1]->ops.dsat};
948 return {
count, sat, dsat};
951 const auto count{3 +
subs[0]->ops.count +
subs[1]->ops.count};
952 const auto sat{
subs[0]->ops.sat | (
subs[1]->ops.sat +
subs[0]->ops.dsat)};
953 const auto dsat{
subs[0]->ops.dsat +
subs[1]->ops.dsat};
954 return {
count, sat, dsat};
957 const auto count{2 +
subs[0]->ops.count +
subs[1]->ops.count};
958 const auto sat{
subs[0]->ops.sat | (
subs[1]->ops.sat +
subs[0]->ops.dsat)};
959 return {
count, sat, {}};
962 const auto count{3 +
subs[0]->ops.count +
subs[1]->ops.count};
963 const auto sat{
subs[0]->ops.sat |
subs[1]->ops.sat};
964 const auto dsat{
subs[0]->ops.dsat |
subs[1]->ops.dsat};
965 return {
count, sat, dsat};
968 const auto count{3 +
subs[0]->ops.count +
subs[1]->ops.count +
subs[2]->ops.count};
970 const auto dsat{
subs[0]->ops.dsat +
subs[2]->ops.dsat};
971 return {
count, sat, dsat};
985 for (
const auto& sub :
subs) {
986 count += sub->ops.count + 1;
987 auto next_sats =
Vector(sats[0] + sub->ops.dsat);
988 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub->ops.dsat) | (sats[j - 1] + sub->ops.sat));
989 next_sats.push_back(sats[sats.size() - 1] + sub->ops.sat);
990 sats = std::move(next_sats);
993 return {
count, sats[
k], sats[0]};
1000 using namespace internal;
1016 const auto& x{subs[0]->ss};
1017 const auto& y{subs[1]->ss};
1018 const auto& z{subs[2]->ss};
1020 (x.sat + SatInfo::If() + y.sat) | (x.dsat + SatInfo::If() + z.sat),
1021 x.dsat + SatInfo::If() + z.dsat
1025 const auto& x{subs[0]->ss};
1026 const auto& y{subs[1]->ss};
1027 return {x.sat + y.sat, {}};
1030 const auto& x{subs[0]->ss};
1031 const auto& y{subs[1]->ss};
1032 return {x.sat + y.sat + SatInfo::BinaryOp(), x.dsat + y.dsat + SatInfo::BinaryOp()};
1035 const auto& x{subs[0]->ss};
1036 const auto& y{subs[1]->ss};
1038 ((x.sat + y.dsat) | (x.dsat + y.sat)) + SatInfo::BinaryOp(),
1039 x.dsat + y.dsat + SatInfo::BinaryOp()
1043 const auto& x{subs[0]->ss};
1044 const auto& y{subs[1]->ss};
1045 return {(x.sat + SatInfo::If()) | (x.dsat + SatInfo::If() + y.sat), {}};
1048 const auto& x{subs[0]->ss};
1049 const auto& y{subs[1]->ss};
1056 const auto& x{subs[0]->ss};
1057 const auto& y{subs[1]->ss};
1058 return {SatInfo::If() + (x.sat | y.sat), SatInfo::If() + (x.dsat | y.dsat)};
1087 auto sats =
Vector(SatInfo::Empty());
1088 for (
size_t i = 0; i < subs.size(); ++i) {
1091 auto add = i ? SatInfo::BinaryOp() : SatInfo::Empty();
1093 auto next_sats =
Vector(sats[0] + subs[i]->ss.dsat + add);
1095 for (
size_t j = 1; j < sats.size(); ++j) {
1096 next_sats.push_back(((sats[j] + subs[i]->ss.dsat) | (sats[j - 1] + subs[i]->ss.sat)) + add);
1099 next_sats.push_back(sats[sats.size() - 1] + subs[i]->ss.sat + add);
1101 sats = std::move(next_sats);
1116 const uint32_t pubkey_size =
IsTapscript(m_script_ctx) ? 1 + 32 : 1 + 33;
1129 const auto sat{(subs[0]->ws.sat + subs[1]->ws.sat) | (subs[0]->ws.dsat + subs[2]->ws.sat)};
1130 const auto dsat{subs[0]->ws.dsat + subs[2]->ws.dsat};
1134 case Fragment::AND_B:
return {subs[0]->ws.sat + subs[1]->ws.sat, subs[0]->ws.dsat + subs[1]->ws.dsat};
1136 const auto sat{(subs[0]->ws.dsat + subs[1]->ws.sat) | (subs[0]->ws.sat + subs[1]->ws.dsat)};
1137 const auto dsat{subs[0]->ws.dsat + subs[1]->ws.dsat};
1140 case Fragment::OR_C:
return {subs[0]->ws.sat | (subs[0]->ws.dsat + subs[1]->ws.sat), {}};
1141 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};
1142 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)};
1154 for (
const auto& sub : subs) {
1155 auto next_sats =
Vector(sats[0] + sub->ws.dsat);
1156 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub->ws.dsat) | (sats[j - 1] + sub->ws.sat));
1157 next_sats.push_back(sats[sats.size() - 1] + sub->ws.sat);
1158 sats = std::move(next_sats);
1161 return {sats[
k], sats[0]};
1167 template<
typename Ctx>
1169 using namespace internal;
1174 switch (
node.fragment) {
1176 std::vector<unsigned char> sig;
1178 return {
ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
1181 std::vector<unsigned char> key = ctx.ToPKBytes(
node.keys[0]), sig;
1183 return {
ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
1189 for (
size_t i = 0; i <
node.keys.size(); ++i) {
1192 std::vector<unsigned char> sig;
1195 auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1199 std::vector<InputStack> next_sats;
1200 next_sats.push_back(sats[0] +
ZERO);
1201 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] +
ZERO) | (std::move(sats[j - 1]) + sat));
1202 next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1204 sats = std::move(next_sats);
1208 auto& nsat{sats[0]};
1211 return {std::move(nsat), std::move(sats[
node.k])};
1218 for (
size_t i = 0; i <
node.keys.size(); ++i) {
1219 std::vector<unsigned char> sig;
1222 auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1226 std::vector<InputStack> next_sats;
1227 next_sats.push_back(sats[0]);
1228 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
1229 next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1231 sats = std::move(next_sats);
1234 InputStack nsat =
ZERO;
1235 for (
size_t i = 0; i <
node.k; ++i) nsat = std::move(nsat) +
ZERO;
1237 return {std::move(nsat), std::move(sats[
node.k])};
1244 for (
size_t i = 0; i < subres.size(); ++i) {
1246 auto& res = subres[subres.size() - i - 1];
1250 std::vector<InputStack> next_sats;
1251 next_sats.push_back(sats[0] + res.nsat);
1252 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + res.nsat) | (std::move(sats[j - 1]) + res.sat));
1253 next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
1255 sats = std::move(next_sats);
1259 InputStack nsat = INVALID;
1260 for (
size_t i = 0; i < sats.size(); ++i) {
1267 if (i != 0 && i !=
node.k) sats[i].SetMalleable().SetNonCanon();
1269 if (i !=
node.k) nsat = std::move(nsat) | std::move(sats[i]);
1272 return {std::move(nsat), std::move(sats[
node.k])};
1275 return {INVALID, ctx.CheckOlder(
node.k) ?
EMPTY : INVALID};
1278 return {INVALID, ctx.CheckAfter(
node.k) ?
EMPTY : INVALID};
1281 std::vector<unsigned char> preimage;
1283 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1286 std::vector<unsigned char> preimage;
1288 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1291 std::vector<unsigned char> preimage;
1293 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1296 std::vector<unsigned char> preimage;
1298 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1301 auto& x = subres[0], &y = subres[1];
1308 return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
1311 auto& x = subres[0], &y = subres[1];
1317 return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
1320 auto& x = subres[0], &z = subres[1];
1322 return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
1325 auto& x = subres[0], &z = subres[1];
1326 return {INVALID, std::move(x.sat) | (z.sat + x.nsat)};
1329 auto& x = subres[0], &z = subres[1];
1330 return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
1333 auto& x = subres[0], &z = subres[1];
1334 return {(x.nsat +
ONE) | (z.nsat +
ZERO), (x.sat +
ONE) | (z.sat +
ZERO)};
1337 auto& x = subres[0], &y = subres[1], &z = subres[2];
1338 return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
1344 return std::move(subres[0]);
1346 auto &x = subres[0];
1350 auto &x = subres[0];
1356 return {InputStack(
ZERO).SetMalleable(x.nsat.available !=
Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
1359 auto &x = subres[0];
1360 return {INVALID, std::move(x.sat)};
1366 return {INVALID, INVALID};
1370 auto ret = helper(
node, subres);
1393 if (
node.GetType() <<
"d"_mst && !
ret.nsat.malleable)
assert(!
ret.nsat.non_canon);
1401 if (
node.GetType() <<
"me"_mst)
assert(!
ret.nsat.malleable);
1412 return TreeEval<InputResult>(tester);
1427 Comp(
const Ctx& ctx) : ctx_ptr(&ctx) {}
1428 bool operator()(
const Key& a,
const Key& b)
const {
return ctx_ptr->KeyCompare(a, b); }
1434 using keyset = std::set<Key, Comp>;
1435 using state = std::optional<keyset>;
1439 if (
node.has_duplicate_keys.has_value() && *
node.has_duplicate_keys)
return {};
1442 for (
auto& sub : subs) {
1443 if (!sub.has_value()) {
1444 node.has_duplicate_keys =
true;
1451 size_t keys_count =
node.keys.size();
1452 keyset key_set{
node.keys.begin(),
node.keys.end(), Comp(ctx)};
1453 if (key_set.size() != keys_count) {
1455 node.has_duplicate_keys =
true;
1460 for (
auto& sub : subs) {
1461 keys_count += sub->size();
1464 if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1465 key_set.merge(*sub);
1466 if (key_set.size() != keys_count) {
1467 node.has_duplicate_keys =
true;
1472 node.has_duplicate_keys =
false;
1476 TreeEval<state>(upfn);
1484 if (!ops.sat.valid)
return {};
1485 return ops.count + ops.sat.value;
1500 return !((GetType() &
"BKW"_mst) ==
""_mst);
1505 if (!ss.sat.valid)
return {};
1506 return ss.sat.netdiff +
static_cast<int32_t
>(IsBKW());
1511 if (!ss.sat.valid)
return {};
1512 return ss.sat.exec +
static_cast<int32_t
>(IsBKW());
1520 if (
const auto exec_ss = GetExecStackSize())
return exec_ss <=
MAX_STACK_SIZE;
1533 if (!ws.sat.valid)
return {};
1534 return ws.sat.value;
1546 for (
auto& sub: subs)
if (sub)
return sub;
1547 if (!
node.IsSaneSubexpression())
return &
node;
1554 template<
typename F>
1559 switch (
node.fragment) {
1560 case Fragment::JUST_0:
1562 case Fragment::JUST_1:
1564 case Fragment::PK_K:
1565 case Fragment::PK_H:
1566 case Fragment::MULTI:
1567 case Fragment::MULTI_A:
1568 case Fragment::AFTER:
1569 case Fragment::OLDER:
1570 case Fragment::HASH256:
1571 case Fragment::HASH160:
1572 case Fragment::SHA256:
1573 case Fragment::RIPEMD160:
1574 return bool{fn(node)};
1576 return (subs[0] && subs[1]) || subs[2];
1579 return subs[0] && subs[1];
1584 return subs[0] || subs[1];
1586 return static_cast<uint32_t
>(
std::count(subs.begin(), subs.end(),
true)) >=
node.k;
1588 assert(subs.size() == 1);
1596 if (GetType() ==
""_mst)
return false;
1619 bool IsSaneSubexpression()
const {
return ValidSatisfactions() && IsNonMalleable() && CheckTimeLocksMix() && CheckDuplicateKey(); }
1622 bool IsSane()
const {
return IsValidTopLevel() && IsSaneSubexpression() && NeedsSignature(); }
1628 template<
typename Ctx>
1629 Availability Satisfy(
const Ctx& ctx, std::vector<std::vector<unsigned char>>& stack,
bool nonmalleable =
true)
const {
1630 auto ret = ProduceInput(ctx);
1631 if (nonmalleable && (
ret.sat.malleable || !
ret.sat.has_sig))
return Availability::NO;
1632 stack = std::move(
ret.sat.stack);
1633 return ret.sat.available;
1641 : 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()) {}
1643 : fragment(nt),
k(val),
data(
std::move(arg)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1645 : 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()) {}
1647 : fragment(nt),
k(val), keys(
std::move(key)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1649 : fragment(nt),
k(val), subs(
std::move(sub)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1651 : fragment(nt),
k(val), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1654 template <
typename Ctx>
Node(
const Ctx& ctx,
Fragment nt, std::vector<
NodeRef<Key>> sub, std::vector<unsigned char> arg, uint32_t val = 0)
1655 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(sub),
std::move(arg), val) { DuplicateKeyCheck(ctx); }
1656 template <
typename Ctx>
Node(
const Ctx& ctx,
Fragment nt, std::vector<unsigned char> arg, uint32_t val = 0)
1657 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(arg), val) { DuplicateKeyCheck(ctx);}
1659 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(sub),
std::move(key), val) { DuplicateKeyCheck(ctx); }
1660 template <
typename Ctx>
Node(
const Ctx& ctx,
Fragment nt, std::vector<Key> key, uint32_t val = 0)
1661 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(key), val) { DuplicateKeyCheck(ctx); }
1663 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(sub), val) { DuplicateKeyCheck(ctx); }
1664 template <
typename Ctx>
Node(
const Ctx& ctx,
Fragment nt, uint32_t val = 0)
1665 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt, val) { DuplicateKeyCheck(ctx); }
1727template<
typename Key,
typename Ctx>
1731 if (key_size < 1)
return {};
1732 auto key = ctx.FromString(in.
begin(), in.
begin() + key_size);
1733 if (!key)
return {};
1734 return {{std::move(*key), key_size}};
1738template<
typename Ctx>
1743 if (hash_size < 1)
return {};
1744 std::string val = std::string(in.
begin(), in.
begin() + hash_size);
1745 if (!
IsHex(val))
return {};
1747 if (hash.size() != expected_size)
return {};
1748 return {{std::move(hash), hash_size}};
1752template<
typename Key>
1756 constructed.pop_back();
1758 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, script_ctx, nt,
Vector(std::move(child), std::move(constructed.back())));
1760 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, script_ctx, nt,
Vector(std::move(constructed.back()), std::move(child)));
1769template<
typename Key,
typename Ctx>
1784 size_t script_size{1};
1788 std::vector<std::tuple<ParseContext, int64_t, int64_t>> to_parse;
1789 std::vector<NodeRef<Key>> constructed;
1791 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
1794 const auto parse_multi_exp = [&](
Span<const char>& in,
const bool is_multi_a) ->
bool {
1796 const auto required_ctx{is_multi_a ? MiniscriptContext::TAPSCRIPT : MiniscriptContext::P2WSH};
1797 if (ctx.MsContext() != required_ctx)
return false;
1800 if (next_comma < 1)
return false;
1801 const auto k_to_integral{ToIntegral<int64_t>(std::string_view(in.
begin(), next_comma))};
1802 if (!k_to_integral.has_value())
return false;
1803 const int64_t
k{k_to_integral.value()};
1804 in = in.
subspan(next_comma + 1);
1806 std::vector<Key> keys;
1807 while (next_comma != -1) {
1809 int key_length = (next_comma == -1) ?
FindNextChar(in,
')') : next_comma;
1810 if (key_length < 1)
return false;
1811 auto key = ctx.FromString(in.
begin(), in.
begin() + key_length);
1812 if (!key)
return false;
1813 keys.push_back(std::move(*key));
1814 in = in.
subspan(key_length + 1);
1816 if (keys.size() < 1 || keys.size() > max_keys)
return false;
1817 if (k < 1 || k > (int64_t)keys.size())
return false;
1821 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys),
k));
1823 script_size += 2 + (keys.size() > 16) + (
k > 16) + 34 * keys.size();
1824 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys),
k));
1829 while (!to_parse.empty()) {
1830 if (script_size > max_size)
return {};
1833 auto [cur_context, n,
k] = to_parse.back();
1834 to_parse.pop_back();
1836 switch (cur_context) {
1837 case ParseContext::WRAPPED_EXPR: {
1838 std::optional<size_t> colon_index{};
1839 for (
size_t i = 1; i < in.
size(); ++i) {
1844 if (in[i] <
'a' || in[i] >
'z')
break;
1847 bool last_was_v{
false};
1848 for (
size_t j = 0; colon_index && j < *colon_index; ++j) {
1849 if (script_size > max_size)
return {};
1852 to_parse.emplace_back(ParseContext::ALT, -1, -1);
1853 }
else if (in[j] ==
's') {
1855 to_parse.emplace_back(ParseContext::SWAP, -1, -1);
1856 }
else if (in[j] ==
'c') {
1859 }
else if (in[j] ==
'd') {
1861 to_parse.emplace_back(ParseContext::DUP_IF, -1, -1);
1862 }
else if (in[j] ==
'j') {
1864 to_parse.emplace_back(ParseContext::NON_ZERO, -1, -1);
1865 }
else if (in[j] ==
'n') {
1867 to_parse.emplace_back(ParseContext::ZERO_NOTEQUAL, -1, -1);
1868 }
else if (in[j] ==
'v') {
1871 if (last_was_v)
return {};
1872 to_parse.emplace_back(ParseContext::VERIFY, -1, -1);
1873 }
else if (in[j] ==
'u') {
1875 to_parse.emplace_back(ParseContext::WRAP_U, -1, -1);
1876 }
else if (in[j] ==
't') {
1878 to_parse.emplace_back(ParseContext::WRAP_T, -1, -1);
1879 }
else if (in[j] ==
'l') {
1882 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0));
1883 to_parse.emplace_back(ParseContext::OR_I, -1, -1);
1887 last_was_v = (in[j] ==
'v');
1889 to_parse.emplace_back(ParseContext::EXPR, -1, -1);
1890 if (colon_index) in = in.
subspan(*colon_index + 1);
1893 case ParseContext::EXPR: {
1894 if (
Const(
"0", in)) {
1895 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0));
1896 }
else if (
Const(
"1", in)) {
1897 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1));
1898 }
else if (
Const(
"pk(", in)) {
1899 auto res = ParseKeyEnd<Key, Ctx>(in, ctx);
1900 if (!res)
return {};
1901 auto& [key, key_size] = *res;
1903 in = in.
subspan(key_size + 1);
1904 script_size +=
IsTapscript(ctx.MsContext()) ? 33 : 34;
1905 }
else if (
Const(
"pkh(", in)) {
1906 auto res = ParseKeyEnd<Key>(in, ctx);
1907 if (!res)
return {};
1908 auto& [key, key_size] = *res;
1910 in = in.
subspan(key_size + 1);
1912 }
else if (
Const(
"pk_k(", in)) {
1913 auto res = ParseKeyEnd<Key>(in, ctx);
1914 if (!res)
return {};
1915 auto& [key, key_size] = *res;
1917 in = in.
subspan(key_size + 1);
1918 script_size +=
IsTapscript(ctx.MsContext()) ? 32 : 33;
1919 }
else if (
Const(
"pk_h(", in)) {
1920 auto res = ParseKeyEnd<Key>(in, ctx);
1921 if (!res)
return {};
1922 auto& [key, key_size] = *res;
1924 in = in.
subspan(key_size + 1);
1926 }
else if (
Const(
"sha256(", in)) {
1928 if (!res)
return {};
1929 auto& [hash, hash_size] = *res;
1930 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, std::move(hash)));
1931 in = in.
subspan(hash_size + 1);
1933 }
else if (
Const(
"ripemd160(", in)) {
1935 if (!res)
return {};
1936 auto& [hash, hash_size] = *res;
1938 in = in.
subspan(hash_size + 1);
1940 }
else if (
Const(
"hash256(", in)) {
1942 if (!res)
return {};
1943 auto& [hash, hash_size] = *res;
1944 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, std::move(hash)));
1945 in = in.
subspan(hash_size + 1);
1947 }
else if (
Const(
"hash160(", in)) {
1949 if (!res)
return {};
1950 auto& [hash, hash_size] = *res;
1951 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, std::move(hash)));
1952 in = in.
subspan(hash_size + 1);
1954 }
else if (
Const(
"after(", in)) {
1956 if (arg_size < 1)
return {};
1957 const auto num{ToIntegral<int64_t>(std::string_view(in.
begin(), arg_size))};
1958 if (!num.has_value() || *num < 1 || *num >= 0x80000000L)
return {};
1959 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num));
1960 in = in.
subspan(arg_size + 1);
1961 script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
1962 }
else if (
Const(
"older(", in)) {
1964 if (arg_size < 1)
return {};
1965 const auto num{ToIntegral<int64_t>(std::string_view(in.
begin(), arg_size))};
1966 if (!num.has_value() || *num < 1 || *num >= 0x80000000L)
return {};
1967 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num));
1968 in = in.
subspan(arg_size + 1);
1969 script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
1970 }
else if (
Const(
"multi(", in)) {
1971 if (!parse_multi_exp(in,
false))
return {};
1972 }
else if (
Const(
"multi_a(", in)) {
1973 if (!parse_multi_exp(in,
true))
return {};
1974 }
else if (
Const(
"thresh(", in)) {
1976 if (next_comma < 1)
return {};
1977 const auto k{ToIntegral<int64_t>(std::string_view(in.
begin(), next_comma))};
1978 if (!
k.has_value() || *
k < 1)
return {};
1979 in = in.
subspan(next_comma + 1);
1981 to_parse.emplace_back(ParseContext::THRESH, 1, *
k);
1982 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
1983 script_size += 2 + (*
k > 16) + (*
k > 0x7f) + (*
k > 0x7fff) + (*
k > 0x7fffff);
1984 }
else if (
Const(
"andor(", in)) {
1985 to_parse.emplace_back(ParseContext::ANDOR, -1, -1);
1986 to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
1987 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
1988 to_parse.emplace_back(ParseContext::COMMA, -1, -1);
1989 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
1990 to_parse.emplace_back(ParseContext::COMMA, -1, -1);
1991 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
1994 if (
Const(
"and_n(", in)) {
1995 to_parse.emplace_back(ParseContext::AND_N, -1, -1);
1997 }
else if (
Const(
"and_b(", in)) {
1998 to_parse.emplace_back(ParseContext::AND_B, -1, -1);
2000 }
else if (
Const(
"and_v(", in)) {
2001 to_parse.emplace_back(ParseContext::AND_V, -1, -1);
2003 }
else if (
Const(
"or_b(", in)) {
2004 to_parse.emplace_back(ParseContext::OR_B, -1, -1);
2006 }
else if (
Const(
"or_c(", in)) {
2007 to_parse.emplace_back(ParseContext::OR_C, -1, -1);
2009 }
else if (
Const(
"or_d(", in)) {
2010 to_parse.emplace_back(ParseContext::OR_D, -1, -1);
2012 }
else if (
Const(
"or_i(", in)) {
2013 to_parse.emplace_back(ParseContext::OR_I, -1, -1);
2018 to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
2019 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2020 to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2021 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2025 case ParseContext::ALT: {
2026 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A,
Vector(std::move(constructed.back())));
2029 case ParseContext::SWAP: {
2030 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S,
Vector(std::move(constructed.back())));
2034 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C,
Vector(std::move(constructed.back())));
2037 case ParseContext::DUP_IF: {
2038 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D,
Vector(std::move(constructed.back())));
2041 case ParseContext::NON_ZERO: {
2042 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J,
Vector(std::move(constructed.back())));
2045 case ParseContext::ZERO_NOTEQUAL: {
2046 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N,
Vector(std::move(constructed.back())));
2049 case ParseContext::VERIFY: {
2050 script_size += (constructed.back()->GetType() <<
"x"_mst);
2051 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V,
Vector(std::move(constructed.back())));
2054 case ParseContext::WRAP_U: {
2058 case ParseContext::WRAP_T: {
2062 case ParseContext::AND_B: {
2063 BuildBack(ctx.MsContext(), Fragment::AND_B, constructed);
2066 case ParseContext::AND_N: {
2067 auto mid = std::move(constructed.back());
2068 constructed.pop_back();
2069 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)));
2072 case ParseContext::AND_V: {
2073 BuildBack(ctx.MsContext(), Fragment::AND_V, constructed);
2076 case ParseContext::OR_B: {
2077 BuildBack(ctx.MsContext(), Fragment::OR_B, constructed);
2080 case ParseContext::OR_C: {
2081 BuildBack(ctx.MsContext(), Fragment::OR_C, constructed);
2084 case ParseContext::OR_D: {
2085 BuildBack(ctx.MsContext(), Fragment::OR_D, constructed);
2088 case ParseContext::OR_I: {
2089 BuildBack(ctx.MsContext(), Fragment::OR_I, constructed);
2092 case ParseContext::ANDOR: {
2093 auto right = std::move(constructed.back());
2094 constructed.pop_back();
2095 auto mid = std::move(constructed.back());
2096 constructed.pop_back();
2097 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR,
Vector(std::move(constructed.back()), std::move(mid), std::move(right)));
2100 case ParseContext::THRESH: {
2101 if (in.
size() < 1)
return {};
2104 to_parse.emplace_back(ParseContext::THRESH, n+1,
k);
2105 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2107 }
else if (in[0] ==
')') {
2108 if (
k > n)
return {};
2111 std::vector<NodeRef<Key>> subs;
2112 for (
int i = 0; i < n; ++i) {
2113 subs.push_back(std::move(constructed.back()));
2114 constructed.pop_back();
2116 std::reverse(subs.begin(), subs.end());
2117 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs),
k));
2123 case ParseContext::COMMA: {
2124 if (in.
size() < 1 || in[0] !=
',')
return {};
2128 case ParseContext::CLOSE_BRACKET: {
2129 if (in.
size() < 1 || in[0] !=
')')
return {};
2137 assert(constructed.size() == 1);
2138 assert(constructed[0]->ScriptSize() == script_size);
2139 if (in.
size() > 0)
return {};
2141 tl_node->DuplicateKeyCheck(ctx);
2227template<
typename Key,
typename Ctx,
typename I>
2231 std::vector<std::tuple<DecodeContext, int64_t, int64_t>> to_parse;
2232 std::vector<NodeRef<Key>> constructed;
2236 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2238 while (!to_parse.empty()) {
2240 if (!constructed.empty() && !constructed.back()->IsValid())
return {};
2243 auto [cur_context, n,
k] = to_parse.back();
2244 to_parse.pop_back();
2246 switch(cur_context) {
2247 case DecodeContext::SINGLE_BKV_EXPR: {
2248 if (in >= last)
return {};
2251 if (in[0].first ==
OP_1) {
2253 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1));
2256 if (in[0].first ==
OP_0) {
2258 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0));
2262 if (in[0].second.size() == 33 || in[0].second.size() == 32) {
2263 auto key = ctx.FromPKBytes(in[0].second.begin(), in[0].second.end());
2264 if (!key)
return {};
2270 auto key = ctx.FromPKHBytes(in[2].second.begin(), in[2].second.end());
2271 if (!key)
return {};
2277 std::optional<int64_t> num;
2280 if (*num < 1 || *num > 0x7FFFFFFFL)
return {};
2281 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num));
2286 if (num < 1 || num > 0x7FFFFFFFL)
return {};
2287 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num));
2292 if (in[2].first ==
OP_SHA256 && in[1].second.size() == 32) {
2293 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, in[1].second));
2296 }
else if (in[2].first ==
OP_RIPEMD160 && in[1].second.size() == 20) {
2300 }
else if (in[2].first ==
OP_HASH256 && in[1].second.size() == 32) {
2301 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, in[1].second));
2304 }
else if (in[2].first ==
OP_HASH160 && in[1].second.size() == 20) {
2305 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, in[1].second));
2313 std::vector<Key> keys;
2315 if (!n || last - in < 3 + *n)
return {};
2316 if (*n < 1 || *n > 20)
return {};
2317 for (
int i = 0; i < *n; ++i) {
2318 if (in[2 + i].second.size() != 33)
return {};
2319 auto key = ctx.FromPKBytes(in[2 + i].second.begin(), in[2 + i].second.end());
2320 if (!key)
return {};
2321 keys.push_back(std::move(*key));
2324 if (!
k || *k < 1 || *k > *n)
return {};
2326 std::reverse(keys.begin(), keys.end());
2327 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), *
k));
2331 if (last - in >= 4 && in[0].first ==
OP_NUMEQUAL) {
2337 if (last - in < 2 + *
k * 2)
return {};
2338 std::vector<Key> keys;
2341 for (
int pos = 2;; pos += 2) {
2342 if (last - in < pos + 2)
return {};
2345 if (in[pos + 1].second.size() != 32)
return {};
2346 auto key = ctx.FromPKBytes(in[pos + 1].second.begin(), in[pos + 1].second.end());
2347 if (!key)
return {};
2348 keys.push_back(std::move(*key));
2354 if (keys.size() < (
size_t)*
k)
return {};
2355 in += 2 + keys.size() * 2;
2356 std::reverse(keys.begin(), keys.end());
2357 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), *
k));
2367 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2373 to_parse.emplace_back(DecodeContext::VERIFY, -1, -1);
2374 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2380 to_parse.emplace_back(DecodeContext::ZERO_NOTEQUAL, -1, -1);
2381 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2386 if (*num < 1)
return {};
2388 to_parse.emplace_back(DecodeContext::THRESH_W, 0, *num);
2394 to_parse.emplace_back(DecodeContext::ENDIF, -1, -1);
2395 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2406 to_parse.emplace_back(DecodeContext::AND_B, -1, -1);
2407 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2408 to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2414 to_parse.emplace_back(DecodeContext::OR_B, -1, -1);
2415 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2416 to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2422 case DecodeContext::BKV_EXPR: {
2423 to_parse.emplace_back(DecodeContext::MAYBE_AND_V, -1, -1);
2424 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2427 case DecodeContext::W_EXPR: {
2429 if (in >= last)
return {};
2432 to_parse.emplace_back(DecodeContext::ALT, -1, -1);
2434 to_parse.emplace_back(DecodeContext::SWAP, -1, -1);
2436 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2439 case DecodeContext::MAYBE_AND_V: {
2443 to_parse.emplace_back(DecodeContext::AND_V, -1, -1);
2445 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2449 case DecodeContext::SWAP: {
2450 if (in >= last || in[0].first !=
OP_SWAP || constructed.empty())
return {};
2452 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_S,
Vector(std::move(constructed.back())));
2455 case DecodeContext::ALT: {
2456 if (in >= last || in[0].first !=
OP_TOALTSTACK || constructed.empty())
return {};
2458 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_A,
Vector(std::move(constructed.back())));
2462 if (constructed.empty())
return {};
2463 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_C,
Vector(std::move(constructed.back())));
2466 case DecodeContext::DUP_IF: {
2467 if (constructed.empty())
return {};
2468 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_D,
Vector(std::move(constructed.back())));
2471 case DecodeContext::VERIFY: {
2472 if (constructed.empty())
return {};
2473 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_V,
Vector(std::move(constructed.back())));
2476 case DecodeContext::NON_ZERO: {
2477 if (constructed.empty())
return {};
2478 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_J,
Vector(std::move(constructed.back())));
2481 case DecodeContext::ZERO_NOTEQUAL: {
2482 if (constructed.empty())
return {};
2483 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::WRAP_N,
Vector(std::move(constructed.back())));
2486 case DecodeContext::AND_V: {
2487 if (constructed.size() < 2)
return {};
2488 BuildBack(ctx.MsContext(), Fragment::AND_V, constructed,
true);
2491 case DecodeContext::AND_B: {
2492 if (constructed.size() < 2)
return {};
2493 BuildBack(ctx.MsContext(), Fragment::AND_B, constructed,
true);
2496 case DecodeContext::OR_B: {
2497 if (constructed.size() < 2)
return {};
2498 BuildBack(ctx.MsContext(), Fragment::OR_B, constructed,
true);
2501 case DecodeContext::OR_C: {
2502 if (constructed.size() < 2)
return {};
2503 BuildBack(ctx.MsContext(), Fragment::OR_C, constructed,
true);
2506 case DecodeContext::OR_D: {
2507 if (constructed.size() < 2)
return {};
2508 BuildBack(ctx.MsContext(), Fragment::OR_D, constructed,
true);
2511 case DecodeContext::ANDOR: {
2512 if (constructed.size() < 3)
return {};
2514 constructed.pop_back();
2516 constructed.pop_back();
2518 constructed.back() = MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR,
Vector(std::move(left), std::move(mid), std::move(right)));
2521 case DecodeContext::THRESH_W: {
2522 if (in >= last)
return {};
2523 if (in[0].first ==
OP_ADD) {
2525 to_parse.emplace_back(DecodeContext::THRESH_W, n+1,
k);
2526 to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2528 to_parse.emplace_back(DecodeContext::THRESH_E, n+1,
k);
2530 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2534 case DecodeContext::THRESH_E: {
2535 if (k < 1 || k > n || constructed.size() <
static_cast<size_t>(n))
return {};
2536 std::vector<NodeRef<Key>> subs;
2537 for (
int i = 0; i < n; ++i) {
2539 constructed.pop_back();
2540 subs.push_back(std::move(sub));
2542 constructed.push_back(MakeNodeRef<Key>(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs),
k));
2545 case DecodeContext::ENDIF: {
2546 if (in >= last)
return {};
2551 to_parse.emplace_back(DecodeContext::ENDIF_ELSE, -1, -1);
2552 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2555 else if (in[0].first ==
OP_IF) {
2556 if (last - in >= 2 && in[1].first ==
OP_DUP) {
2558 to_parse.emplace_back(DecodeContext::DUP_IF, -1, -1);
2561 to_parse.emplace_back(DecodeContext::NON_ZERO, -1, -1);
2567 }
else if (in[0].first ==
OP_NOTIF) {
2569 to_parse.emplace_back(DecodeContext::ENDIF_NOTIF, -1, -1);
2576 case DecodeContext::ENDIF_NOTIF: {
2577 if (in >= last)
return {};
2580 to_parse.emplace_back(DecodeContext::OR_D, -1, -1);
2582 to_parse.emplace_back(DecodeContext::OR_C, -1, -1);
2585 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2588 case DecodeContext::ENDIF_ELSE: {
2589 if (in >= last)
return {};
2590 if (in[0].first ==
OP_IF) {
2592 BuildBack(ctx.MsContext(), Fragment::OR_I, constructed,
true);
2593 }
else if (in[0].first ==
OP_NOTIF) {
2595 to_parse.emplace_back(DecodeContext::ANDOR, -1, -1);
2597 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2605 if (constructed.size() != 1)
return {};
2607 tl_node->DuplicateKeyCheck(ctx);
2610 if (!tl_node->IsValidTopLevel())
return {};
2616template<
typename Ctx>
2618 return internal::Parse<typename Ctx::Key>(str, ctx);
2621template<
typename Ctx>
2623 using namespace internal;
2627 if (!decomposed)
return {};
2628 auto it = decomposed->begin();
2629 auto ret = DecodeScript<typename Ctx::Key>(it, decomposed->end(), ctx);
2630 if (!
ret)
return {};
2631 if (it != decomposed->end())
return {};
#define CHECK_NONFATAL(condition)
Identity function.
Serialized script, used inside transaction inputs and outputs.
A Span is an object that can refer to a contiguous sequence of objects.
CONSTEXPR_IF_NOT_DEBUG Span< C > last(std::size_t count) const noexcept
constexpr std::size_t size() const noexcept
CONSTEXPR_IF_NOT_DEBUG Span< C > subspan(std::size_t offset) const noexcept
constexpr C * begin() const noexcept
This type encapsulates the miniscript type system properties.
static consteval Type Make(uint32_t flags) noexcept
Construction function used by the ""_mst operator.
constexpr bool operator<<(Type x) const
Check whether the left hand's properties are superset of the right's (= left is a subtype of right).
uint32_t m_flags
Internal bitmap of properties (see ""_mst operator for details).
constexpr Type If(bool x) const
The empty type if x is false, itself otherwise.
constexpr Type operator&(Type x) const
Compute the type with the intersection of properties.
constexpr bool operator<(Type x) const
Comparison operator to enable use in sets/maps (total ordering incompatible with <<).
constexpr Type operator|(Type x) const
Compute the type with the union of properties.
constexpr bool operator==(Type x) const
Equality operator.
constexpr Type(uint32_t flags) noexcept
Internal constructor.
static const int WITNESS_SCALE_FACTOR
uint160 RIPEMD160(Span< const unsigned char > data)
Compute the 160-bit RIPEMD-160 hash of an array.
uint256 Hash(const T &in1)
Compute the 256-bit hash of an object.
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
@ TAPSCRIPT
Witness v1 with 32-byte program, not BIP16 P2SH-wrapped, script path spending, leaf version 0xc0; see...
static constexpr size_t TAPROOT_CONTROL_MAX_SIZE
#define CHECK(cond)
Unconditional failure on condition failure.
size_t ComputeScriptLen(Fragment fragment, Type sub0typ, size_t subsize, uint32_t k, size_t n_subs, size_t n_keys, MiniscriptContext ms_ctx)
Helper function for Node::CalcScriptLen.
int FindNextChar(Span< const char > sp, const char m)
std::optional< int64_t > ParseScriptNumber(const Opcode &in)
Determine whether the passed pair (created by DecomposeScript) is pushing a number.
Type SanitizeType(Type e)
A helper sanitizer/checker for the output of CalcType.
std::optional< std::vector< Opcode > > DecomposeScript(const CScript &script)
Decode a script into opcode/push pairs.
NodeRef< Key > DecodeScript(I &in, I last, const Ctx &ctx)
Parse a miniscript from a bitcoin script.
NodeRef< Key > Parse(Span< const char > in, const Ctx &ctx)
Parse a miniscript from its textual descriptor form.
constexpr uint32_t TX_BODY_LEEWAY_WEIGHT
Data other than the witness in a transaction. Overhead + vin count + one vin + vout count + one vout ...
constexpr uint32_t TXIN_BYTES_NO_WITNESS
prevout + nSequence + scriptSig
static const auto ONE
A stack consisting of a single 0x01 element (interpreted as 1 by the script interpreted in numeric co...
static const auto ZERO32
A stack consisting of a single malleable 32-byte 0x0000...0000 element (for dissatisfying hash challe...
std::optional< std::pair< std::vector< unsigned char >, int > > ParseHexStrEnd(Span< const char > in, const size_t expected_size, const Ctx &ctx)
Parse a hex string ending at the end of the fragment's text representation.
constexpr uint32_t MaxScriptSize(MiniscriptContext ms_ctx)
The maximum size of a script depending on the context.
constexpr uint32_t TX_OVERHEAD
version + nLockTime
static const auto ZERO
A stack consisting of a single zero-length element (interpreted as 0 by the script interpreter in num...
std::optional< std::pair< Key, int > > ParseKeyEnd(Span< const char > in, const Ctx &ctx)
Parse a key string ending at the end of the fragment's text representation.
constexpr uint32_t P2WSH_TXOUT_BYTES
nValue + script len + OP_0 + pushdata 32.
@ VERIFY
VERIFY wraps the top constructed node with v:
@ CLOSE_BRACKET
CLOSE_BRACKET expects the next element to be ')' and fails if not.
@ AND_N
AND_N will construct an andor(X,Y,0) node from the last two constructed nodes.
@ SWAP
SWAP wraps the top constructed node with s:
@ COMMA
COMMA expects the next element to be ',' and fails if not.
@ DUP_IF
DUP_IF wraps the top constructed node with d:
@ EXPR
A miniscript expression which does not begin with wrappers.
@ ZERO_NOTEQUAL
ZERO_NOTEQUAL wraps the top constructed node with n:
@ NON_ZERO
NON_ZERO wraps the top constructed node with j:
@ WRAP_T
WRAP_T will construct an and_v(X,1) node from the top constructed node.
@ ALT
ALT wraps the top constructed node with a:
@ WRAP_U
WRAP_U will construct an or_i(X,0) node from the top constructed node.
@ WRAPPED_EXPR
An expression which may be begin with wrappers followed by a colon.
static const auto INVALID
A stack representing the lack of any (dis)satisfactions.
@ SINGLE_BKV_EXPR
A single expression of type B, K, or V.
@ ENDIF_NOTIF
If, inside an ENDIF context, we find an OP_NOTIF before finding an OP_ELSE, we could either be in an ...
@ BKV_EXPR
Potentially multiple SINGLE_BKV_EXPRs as children of (potentially multiple) and_v expressions.
@ ENDIF_ELSE
If, inside an ENDIF context, we find an OP_ELSE, then we could be in either an or_i or an andor node.
@ MAYBE_AND_V
MAYBE_AND_V will check if the next part of the script could be a valid miniscript sub-expression,...
@ W_EXPR
An expression of type W (a: or s: wrappers).
@ THRESH_E
THRESH_E constructs a thresh node from the appropriate number of constructed children.
@ ENDIF
ENDIF signals that we are inside some sort of OP_IF structure, which could be or_d,...
@ THRESH_W
In a thresh expression, all sub-expressions other than the first are W-type, and end in OP_ADD.
constexpr uint32_t MAX_TAPSCRIPT_SAT_SIZE
Maximum possible stack size to spend a Taproot output (excluding the script itself).
static const auto EMPTY
The empty stack.
Type ComputeType(Fragment fragment, Type x, Type y, Type z, const std::vector< Type > &sub_types, uint32_t k, size_t data_size, size_t n_subs, size_t n_keys, MiniscriptContext ms_ctx)
Helper function for Node::CalcType.
void BuildBack(const MiniscriptContext script_ctx, Fragment nt, std::vector< NodeRef< Key > > &constructed, const bool reverse=false)
BuildBack pops the last two elements off constructed and wraps them in the specified Fragment.
static constexpr uint32_t MAX_TAPMINISCRIPT_STACK_ELEM_SIZE
The maximum size of a witness item for a Miniscript under Tapscript context. (A BIP340 signature with...
NodeRef< typename Ctx::Key > FromString(const std::string &str, const Ctx &ctx)
std::shared_ptr< const Node< Key > > NodeRef
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 shared_ptr.
std::pair< opcodetype, std::vector< unsigned char > > Opcode
Fragment
The different node types in miniscript.
@ OR_I
OP_IF [X] OP_ELSE [Y] OP_ENDIF.
@ MULTI_A
[key_0] OP_CHECKSIG ([key_n] OP_CHECKSIGADD)* [k] OP_NUMEQUAL (only within Tapscript ctx)
@ RIPEMD160
OP_SIZE 32 OP_EQUALVERIFY OP_RIPEMD160 [hash] OP_EQUAL.
@ HASH160
OP_SIZE 32 OP_EQUALVERIFY OP_HASH160 [hash] OP_EQUAL.
@ WRAP_A
OP_TOALTSTACK [X] OP_FROMALTSTACK.
@ WRAP_V
[X] OP_VERIFY (or -VERIFY version of last opcode in X)
@ ANDOR
[X] OP_NOTIF [Z] OP_ELSE [Y] OP_ENDIF
@ THRESH
[X1] ([Xn] OP_ADD)* [k] OP_EQUAL
@ OR_C
[X] OP_NOTIF [Y] OP_ENDIF
@ HASH256
OP_SIZE 32 OP_EQUALVERIFY OP_HASH256 [hash] OP_EQUAL.
@ OLDER
[n] OP_CHECKSEQUENCEVERIFY
@ SHA256
OP_SIZE 32 OP_EQUALVERIFY OP_SHA256 [hash] OP_EQUAL.
@ WRAP_J
OP_SIZE OP_0NOTEQUAL OP_IF [X] OP_ENDIF.
@ AFTER
[n] OP_CHECKLOCKTIMEVERIFY
@ OR_D
[X] OP_IFDUP OP_NOTIF [Y] OP_ENDIF
@ WRAP_D
OP_DUP OP_IF [X] OP_ENDIF.
@ AND_B
[X] [Y] OP_BOOLAND
@ PK_H
OP_DUP OP_HASH160 [keyhash] OP_EQUALVERIFY.
@ MULTI
[k] [key_n]* [n] OP_CHECKMULTISIG (only available within P2WSH context)
bool Const(const std::string &str, Span< const char > &sp)
Parse a constant.
std::string ToString(const T &t)
Locale-independent version of std::to_string.
static constexpr unsigned int MAX_STANDARD_P2WSH_STACK_ITEMS
The maximum number of witness stack items in a standard P2WSH script.
static constexpr int32_t MAX_STANDARD_TX_WEIGHT
The maximum weight for transactions we're willing to relay/mine.
static constexpr unsigned int MAX_STANDARD_P2WSH_SCRIPT_SIZE
The maximum size in bytes of a standard witnessScript.
static constexpr unsigned int MAX_PUBKEYS_PER_MULTI_A
The limit of keys in OP_CHECKSIGADD-based scripts.
static const int MAX_STACK_SIZE
static const int MAX_OPS_PER_SCRIPT
CScript BuildScript(Ts &&... inputs)
Build a script by concatenating other scripts, or any argument accepted by CScript::operator<<.
static const int MAX_PUBKEYS_PER_MULTISIG
static bool verify(const CScriptNum10 &bignum, const CScriptNum &scriptnum)
constexpr unsigned int GetSizeOfCompactSize(uint64_t nSize)
Compact Size size < 253 – 1 byte size <= USHRT_MAX – 3 bytes (253 + 2 bytes) size <= UINT_MAX – 5 byt...
std::vector< Byte > ParseHex(std::string_view hex_str)
Like TryParseHex, but returns an empty vector on invalid input.
A node in a miniscript expression.
const Type typ
Cached expression type (computed by CalcType and fed through SanitizeType).
uint32_t GetStaticOps() const
Return the number of ops in the script (not counting the dynamic ones that depend on execution).
Result TreeEval(UpFn upfn) const
Like TreeEval, but without downfn or State type.
const Node * FindInsaneSub() const
Find an insane subnode which has no insane children. Nullptr if there is none.
bool IsBKW() const
Whether this node is of type B, K or W.
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 Ctx &ctx, Fragment nt, uint32_t val=0)
Node(const Ctx &ctx, Fragment nt, std::vector< NodeRef< Key > > sub, std::vector< Key > key, uint32_t val=0)
std::optional< Result > TreeEvalMaybe(UpFn upfn) const
Like TreeEvalMaybe, but without downfn or State type.
internal::WitnessSize CalcWitnessSize() const
Node(internal::NoDupCheck, MiniscriptContext script_ctx, Fragment nt, uint32_t val=0)
Result TreeEval(State root_state, DownFn &&downfn, UpFn upfn) const
Like TreeEvalMaybe, but always produces a result.
internal::Ops CalcOps() const
std::optional< std::string > ToString(const CTx &ctx) const
const MiniscriptContext m_script_ctx
The Script context for this node. Either P2WSH or Tapscript.
size_t CalcScriptLen() const
Compute the length of the script for this miniscript (including children).
std::optional< Result > TreeEvalMaybe(State root_state, DownFn downfn, UpFn upfn) const
bool IsSane() const
Check whether this node is safe as a script on its own.
bool IsValidTopLevel() const
Check whether this node is valid as a script on its own.
bool IsNotSatisfiable() const
Whether no satisfaction exists for this node.
const internal::WitnessSize ws
Cached witness size bounds.
bool IsNonMalleable() const
Check whether this script can always be satisfied in a non-malleable way.
Type CalcType() const
Compute the type for this miniscript.
bool CheckDuplicateKey() const
Check whether there is no duplicate key across this fragment and all its sub-fragments.
Node(const Ctx &ctx, Fragment nt, std::vector< NodeRef< Key > > sub, std::vector< unsigned char > arg, uint32_t val=0)
size_t ScriptSize() const
Return the size of the script for this expression (faster than ToScript().size()).
bool ValidSatisfactions() const
Whether successful non-malleable satisfactions are guaranteed to be valid.
const std::vector< Key > keys
The keys used by this expression (only for PK_K/PK_H/MULTI)
void DuplicateKeyCheck(const Ctx &ctx) const
Update duplicate key information in this Node.
bool operator==(const Node< Key > &arg) const
Equality testing.
Node(internal::NoDupCheck, MiniscriptContext script_ctx, Fragment nt, std::vector< Key > key, uint32_t val=0)
Node(internal::NoDupCheck, MiniscriptContext script_ctx, Fragment nt, std::vector< NodeRef< Key > > sub, std::vector< Key > key, uint32_t val=0)
std::optional< uint32_t > GetOps() const
Return the maximum number of ops needed to satisfy this script non-malleably.
bool CheckTimeLocksMix() const
Check whether there is no satisfaction path that contains both timelocks and heightlocks.
Node(const Ctx &ctx, Fragment nt, std::vector< Key > key, uint32_t val=0)
Node(const Ctx &ctx, Fragment nt, std::vector< unsigned char > arg, uint32_t val=0)
MiniscriptContext GetMsCtx() const
Return the script context for this node.
const internal::Ops ops
Cached ops counts.
bool IsValid() const
Check whether this node is valid at all.
const std::vector< unsigned char > data
The data bytes in this expression (only for HASH160/HASH256/SHA256/RIPEMD10).
const internal::StackSize ss
Cached stack size bounds.
Availability Satisfy(const Ctx &ctx, std::vector< std::vector< unsigned char > > &stack, bool nonmalleable=true) const
Produce a witness for this script, if possible and given the information available in the context.
Node(internal::NoDupCheck, MiniscriptContext script_ctx, Fragment nt, std::vector< NodeRef< Key > > sub, std::vector< unsigned char > arg, uint32_t val=0)
bool IsSatisfiable(F fn) const
Determine whether a Miniscript node is satisfiable.
Class whose objects represent the maximum of a list of integers.
friend MaxInt< I > operator+(const MaxInt< I > &a, const MaxInt< I > &b)
friend MaxInt< I > operator|(const MaxInt< I > &a, const MaxInt< I > &b)
Ops(uint32_t in_count, MaxInt< uint32_t > in_sat, MaxInt< uint32_t > in_dsat)
MaxInt< uint32_t > sat
Number of keys in possibly executed OP_CHECKMULTISIG(VERIFY)s to satisfy.
MaxInt< uint32_t > dsat
Number of keys in possibly executed OP_CHECKMULTISIG(VERIFY)s to dissatisfy.
uint32_t count
Non-push opcodes.
A data structure to help the calculation of stack size limits.
static constexpr SatInfo Nop() noexcept
A script consisting of just a repurposed nop (OP_CHECKLOCKTIMEVERIFY, OP_CHECKSEQUENCEVERIFY).
const int32_t exec
Mow much higher the stack size can be during execution compared to at the end.
static constexpr SatInfo OP_CHECKSIG() noexcept
static constexpr SatInfo BinaryOp() noexcept
A script consisting of just a binary operator (OP_BOOLAND, OP_BOOLOR, OP_ADD).
static constexpr SatInfo OP_VERIFY() noexcept
static constexpr SatInfo Push() noexcept
A script consisting of a single push opcode.
static constexpr SatInfo Empty() noexcept
The empty script.
constexpr SatInfo(int32_t in_netdiff, int32_t in_exec) noexcept
Script set with a single script in it, with specified netdiff and exec.
constexpr friend SatInfo operator|(const SatInfo &a, const SatInfo &b) noexcept
Script set union.
const int32_t netdiff
How much higher the stack size at start of execution can be compared to at the end.
constexpr SatInfo() noexcept
Empty script set.
static constexpr SatInfo OP_EQUALVERIFY() noexcept
static constexpr SatInfo OP_IFDUP(bool nonzero) noexcept
const bool valid
Whether a canonical satisfaction/dissatisfaction is possible at all.
static constexpr SatInfo OP_DUP() noexcept
static constexpr SatInfo OP_0NOTEQUAL() noexcept
static constexpr SatInfo If() noexcept
A script consisting of just OP_IF or OP_NOTIF.
static constexpr SatInfo OP_EQUAL() noexcept
static constexpr SatInfo OP_SIZE() noexcept
static constexpr SatInfo Hash() noexcept
A script consisting of a single hash opcode.
constexpr friend SatInfo operator+(const SatInfo &a, const SatInfo &b) noexcept
Script set concatenation.
constexpr StackSize(SatInfo in_both) noexcept
constexpr StackSize(SatInfo in_sat, SatInfo in_dsat) noexcept
MaxInt< uint32_t > sat
Maximum witness size to satisfy;.
MaxInt< uint32_t > dsat
Maximum witness size to dissatisfy;.
WitnessSize(MaxInt< uint32_t > in_sat, MaxInt< uint32_t > in_dsat)
static const std::vector< uint8_t > EMPTY
bool IsHex(std::string_view str)
std::vector< typename std::common_type< Args... >::type > Vector(Args &&... args)
Construct a vector with the specified elements.