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>
class Node;
196template <
typename Key, std::invocable<const Node<Key>&> Fn>
199 std::vector<std::reference_wrapper<const Node<Key>>> stack{root};
200 while (!stack.empty()) {
202 std::invoke(fn,
node);
204 for (
const auto& sub :
node.Subs()) {
205 stack.emplace_back(sub);
323 std::vector<std::vector<unsigned char>>
stack;
357 template<
typename A,
typename B>
381 if (!a.
valid)
return b;
382 if (!b.
valid)
return a;
453 constexpr SatInfo(int32_t in_netdiff, int32_t in_exec) noexcept :
464 if (!a.valid)
return b;
465 if (!b.valid)
return a;
467 return {std::max(a.netdiff, b.netdiff), std::max(a.exec, b.exec)};
474 if (!a.valid || !b.valid)
return {};
478 return {a.
netdiff + b.netdiff, std::max(b.exec, b.netdiff + a.exec)};
490 static constexpr SatInfo If() noexcept {
return {1, 1}; }
496 static constexpr SatInfo OP_IFDUP(
bool nonzero)
noexcept {
return {nonzero ? -1 : 0, 0}; }
531template <
typename Key>
541 std::vector<unsigned char>
data;
558 std::vector<std::vector<Node>> queue;
559 queue.push_back(std::move(
subs));
561 auto flattening{std::move(queue.back())};
563 for (
Node& n : flattening) {
564 if (!n.subs.empty()) queue.push_back(std::move(n.subs));
566 }
while (!queue.empty());
573 auto upfn = [](
const Node&
node, std::span<Node> children) {
574 std::vector<Node> new_subs;
575 for (
auto& child : children) {
578 new_subs.push_back(std::move(child));
582 return TreeEval<Node>(upfn);
586 uint32_t
K()
const {
return k; }
587 const std::vector<Key>&
Keys()
const {
return keys; }
588 const std::vector<unsigned char>&
Data()
const {
return data; }
589 const std::vector<Node>&
Subs()
const {
return subs; }
613 :
fragment(nt),
k(val),
keys(
std::move(key)),
data(
std::move(arg)),
subs(
std::move(sub)),
m_script_ctx{script_ctx},
ops(
CalcOps()),
ss(
CalcStackSize()),
ws(
CalcWitnessSize()),
typ(
CalcType()),
scriptlen(
CalcScriptLen()) {}
619 for (
const auto& sub :
subs) {
620 subsize += sub.ScriptSize();
622 Type sub0type =
subs.size() > 0 ?
subs[0].GetType() :
""_mst;
649 template<
typename Result,
typename State,
typename DownFn,
typename UpFn>
659 StackElem(
const Node& node_,
size_t exp_,
State&& state_) :
660 node(node_), expanded(exp_), state(std::move(state_)) {}
663 std::vector<StackElem> stack;
666 std::vector<Result> results;
667 stack.emplace_back(*
this, 0, std::move(root_state));
685 while (stack.size()) {
686 const Node&
node = stack.back().node;
687 if (stack.back().expanded <
node.subs.size()) {
691 size_t child_index = stack.back().expanded++;
692 State child_state = downfn(stack.back().state,
node, child_index);
693 stack.emplace_back(
node.subs[child_index], 0, std::move(child_state));
698 std::optional<Result> result{upfn(std::move(stack.back().state),
node,
699 std::span<Result>{results}.last(
node.subs.size()))};
701 if (!result)
return {};
703 results.erase(results.end() -
node.subs.size(), results.end());
704 results.push_back(std::move(*result));
708 assert(results.size() >= 1);
710 return std::move(results[0]);
715 template<
typename Result,
typename UpFn>
718 struct DummyState {};
719 return TreeEvalMaybe<Result>(DummyState{},
720 [](DummyState,
const Node&, size_t) {
return DummyState{}; },
721 [&upfn](DummyState,
const Node&
node, std::span<Result>
subs) {
728 template<
typename Result,
typename State,
typename DownFn,
typename UpFn>
733 return std::move(*TreeEvalMaybe<Result>(std::move(root_state),
734 std::forward<DownFn>(downfn),
737 return std::optional<Result>(std::move(res));
744 template<
typename Result,
typename UpFn>
747 struct DummyState {};
748 return std::move(*TreeEvalMaybe<Result>(DummyState{},
749 [](DummyState,
const Node&, size_t) {
return DummyState{}; },
750 [&upfn](DummyState,
const Node&
node, std::span<Result>
subs) {
752 return std::optional<Result>(std::move(res));
760 std::vector<std::pair<const Node<Key>&,
const Node<Key>&>> queue;
761 queue.emplace_back(node1, node2);
762 while (!queue.empty()) {
763 const auto& [a, b] = queue.back();
765 if (std::tie(a.fragment, a.k, a.keys, a.data) < std::tie(b.fragment, b.k, b.keys, b.data))
return -1;
766 if (std::tie(b.fragment, b.k, b.keys, b.data) < std::tie(a.fragment, a.k, a.keys, a.data))
return 1;
767 if (a.subs.size() < b.subs.size())
return -1;
768 if (b.subs.size() < a.subs.size())
return 1;
769 size_t n = a.
subs.size();
770 for (
size_t i = 0; i < n; ++i) {
771 queue.emplace_back(a.subs[n - 1 - i], b.subs[n - 1 - i]);
779 using namespace internal;
782 std::vector<Type> sub_types;
784 for (
const auto& sub :
subs) sub_types.push_back(sub.GetType());
795 template<
typename Ctx>
814 switch (
node.fragment) {
828 if (
node.subs[0].GetType() <<
"x"_mst) {
831 return std::move(
subs[0]);
848 for (
const auto& key :
node.keys) {
856 for (
auto it =
node.keys.begin() + 1; it !=
node.keys.end(); ++it) {
863 for (
size_t i = 1; i <
subs.size(); ++i) {
871 return TreeEval<CScript>(
false, downfn, upfn);
874 template<
typename CTx>
875 std::optional<std::string>
ToString(
const CTx& ctx)
const {
880 template<
typename CTx>
881 std::optional<std::string>
ToString(
const CTx& ctx,
bool& has_priv_key)
const {
885 auto downfn = [](bool,
const Node&
node, size_t) {
894 auto toString = [&ctx, &has_priv_key](Key key) -> std::optional<std::string> {
895 bool fragment_has_priv_key{
false};
896 auto key_str{ctx.ToString(key, fragment_has_priv_key)};
897 if (key_str) has_priv_key = has_priv_key || fragment_has_priv_key;
903 auto upfn = [is_tapscript, &toString](
bool wrapped,
const Node&
node, std::span<std::string>
subs) -> std::optional<std::string> {
904 std::string
ret = wrapped ?
":" :
"";
906 switch (
node.fragment) {
912 auto key_str = toString(
node.subs[0].keys[0]);
913 if (!key_str)
return {};
914 return std::move(
ret) +
"pk(" + std::move(*key_str) +
")";
918 auto key_str = toString(
node.subs[0].keys[0]);
919 if (!key_str)
return {};
920 return std::move(
ret) +
"pkh(" + std::move(*key_str) +
")";
922 return "c" + std::move(
subs[0]);
937 switch (
node.fragment) {
939 auto key_str = toString(
node.keys[0]);
940 if (!key_str)
return {};
941 return std::move(
ret) +
"pk_k(" + std::move(*key_str) +
")";
944 auto key_str = toString(
node.keys[0]);
945 if (!key_str)
return {};
946 return std::move(
ret) +
"pk_h(" + std::move(*key_str) +
")";
965 return std::move(
ret) +
"andor(" + std::move(
subs[0]) +
"," + std::move(
subs[1]) +
"," + std::move(
subs[2]) +
")";
969 for (
const auto& key :
node.keys) {
970 auto key_str = toString(key);
971 if (!key_str)
return {};
972 str +=
"," + std::move(*key_str);
974 return std::move(str) +
")";
979 for (
const auto& key :
node.keys) {
980 auto key_str = toString(key);
981 if (!key_str)
return {};
982 str +=
"," + std::move(*key_str);
984 return std::move(str) +
")";
988 for (
auto& sub :
subs) {
989 str +=
"," + std::move(sub);
991 return std::move(str) +
")";
998 return TreeEvalMaybe<std::string>(
false, downfn, upfn);
1016 const auto count{1 +
subs[0].ops.count +
subs[1].ops.count};
1017 const auto sat{
subs[0].ops.sat +
subs[1].ops.sat};
1018 const auto dsat{
subs[0].ops.dsat +
subs[1].ops.dsat};
1019 return {
count, sat, dsat};
1022 const auto count{1 +
subs[0].ops.count +
subs[1].ops.count};
1024 const auto dsat{
subs[0].ops.dsat +
subs[1].ops.dsat};
1025 return {
count, sat, dsat};
1028 const auto count{3 +
subs[0].ops.count +
subs[1].ops.count};
1029 const auto sat{
subs[0].ops.sat | (
subs[1].ops.sat +
subs[0].ops.dsat)};
1030 const auto dsat{
subs[0].ops.dsat +
subs[1].ops.dsat};
1031 return {
count, sat, dsat};
1034 const auto count{2 +
subs[0].ops.count +
subs[1].ops.count};
1035 const auto sat{
subs[0].ops.sat | (
subs[1].ops.sat +
subs[0].ops.dsat)};
1036 return {
count, sat, {}};
1039 const auto count{3 +
subs[0].ops.count +
subs[1].ops.count};
1040 const auto sat{
subs[0].ops.sat |
subs[1].ops.sat};
1041 const auto dsat{
subs[0].ops.dsat |
subs[1].ops.dsat};
1042 return {
count, sat, dsat};
1045 const auto count{3 +
subs[0].ops.count +
subs[1].ops.count +
subs[2].ops.count};
1047 const auto dsat{
subs[0].ops.dsat +
subs[2].ops.dsat};
1048 return {
count, sat, dsat};
1062 for (
const auto& sub :
subs) {
1063 count += sub.ops.count + 1;
1064 auto next_sats =
Vector(sats[0] + sub.ops.dsat);
1065 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub.ops.dsat) | (sats[j - 1] + sub.ops.sat));
1066 next_sats.push_back(sats[sats.size() - 1] + sub.ops.sat);
1067 sats = std::move(next_sats);
1070 return {
count, sats[
k], sats[0]};
1077 using namespace internal;
1093 const auto& x{subs[0].ss};
1094 const auto& y{subs[1].ss};
1095 const auto& z{subs[2].ss};
1097 (x.Sat() + SatInfo::If() + y.Sat()) | (x.Dsat() + SatInfo::If() + z.Sat()),
1098 x.Dsat() + SatInfo::If() + z.Dsat()
1102 const auto& x{subs[0].ss};
1103 const auto& y{subs[1].ss};
1104 return {x.Sat() + y.Sat(), {}};
1107 const auto& x{subs[0].ss};
1108 const auto& y{subs[1].ss};
1109 return {x.Sat() + y.Sat() + SatInfo::BinaryOp(), x.Dsat() + y.Dsat() + SatInfo::BinaryOp()};
1112 const auto& x{subs[0].ss};
1113 const auto& y{subs[1].ss};
1115 ((x.Sat() + y.Dsat()) | (x.Dsat() + y.Sat())) + SatInfo::BinaryOp(),
1116 x.Dsat() + y.Dsat() + SatInfo::BinaryOp()
1120 const auto& x{subs[0].ss};
1121 const auto& y{subs[1].ss};
1122 return {(x.Sat() + SatInfo::If()) | (x.Dsat() + SatInfo::If() + y.Sat()), {}};
1125 const auto& x{subs[0].ss};
1126 const auto& y{subs[1].ss};
1133 const auto& x{subs[0].ss};
1134 const auto& y{subs[1].ss};
1135 return {SatInfo::If() + (x.Sat() | y.Sat()), SatInfo::If() + (x.Dsat() | y.Dsat())};
1164 auto sats =
Vector(SatInfo::Empty());
1165 for (
size_t i = 0; i < subs.size(); ++i) {
1168 auto add = i ? SatInfo::BinaryOp() : SatInfo::Empty();
1170 auto next_sats =
Vector(sats[0] + subs[i].ss.Dsat() + add);
1172 for (
size_t j = 1; j < sats.size(); ++j) {
1173 next_sats.push_back(((sats[j] + subs[i].ss.Dsat()) | (sats[j - 1] + subs[i].ss.Sat())) + add);
1176 next_sats.push_back(sats[sats.size() - 1] + subs[i].ss.Sat() + add);
1178 sats = std::move(next_sats);
1193 const uint32_t pubkey_size =
IsTapscript(m_script_ctx) ? 1 + 32 : 1 + 33;
1206 const auto sat{(subs[0].ws.sat + subs[1].ws.sat) | (subs[0].ws.dsat + subs[2].ws.sat)};
1207 const auto dsat{subs[0].ws.dsat + subs[2].ws.dsat};
1211 case Fragment::AND_B:
return {subs[0].ws.sat + subs[1].ws.sat, subs[0].ws.dsat + subs[1].ws.dsat};
1213 const auto sat{(subs[0].ws.dsat + subs[1].ws.sat) | (subs[0].ws.sat + subs[1].ws.dsat)};
1214 const auto dsat{subs[0].ws.dsat + subs[1].ws.dsat};
1217 case Fragment::OR_C:
return {subs[0].ws.sat | (subs[0].ws.dsat + subs[1].ws.sat), {}};
1218 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};
1219 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)};
1231 for (
const auto& sub : subs) {
1232 auto next_sats =
Vector(sats[0] + sub.ws.dsat);
1233 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub.ws.dsat) | (sats[j - 1] + sub.ws.sat));
1234 next_sats.push_back(sats[sats.size() - 1] + sub.ws.sat);
1235 sats = std::move(next_sats);
1238 return {sats[
k], sats[0]};
1244 template<
typename Ctx>
1246 using namespace internal;
1250 auto helper = [&ctx](
const Node&
node, std::span<InputResult> subres) -> InputResult {
1251 switch (
node.fragment) {
1253 std::vector<unsigned char> sig;
1255 return {
ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
1258 std::vector<unsigned char> key = ctx.ToPKBytes(
node.keys[0]), sig;
1260 return {
ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
1266 for (
size_t i = 0; i <
node.keys.size(); ++i) {
1269 std::vector<unsigned char> sig;
1272 auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1276 std::vector<InputStack> next_sats;
1277 next_sats.push_back(sats[0] +
ZERO);
1278 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] +
ZERO) | (std::move(sats[j - 1]) + sat));
1279 next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1281 sats = std::move(next_sats);
1285 auto& nsat{sats[0]};
1288 return {std::move(nsat), std::move(sats[
node.k])};
1295 for (
size_t i = 0; i <
node.keys.size(); ++i) {
1296 std::vector<unsigned char> sig;
1299 auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1303 std::vector<InputStack> next_sats;
1304 next_sats.push_back(sats[0]);
1305 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
1306 next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1308 sats = std::move(next_sats);
1311 InputStack nsat =
ZERO;
1312 for (
size_t i = 0; i <
node.k; ++i) nsat = std::move(nsat) +
ZERO;
1314 return {std::move(nsat), std::move(sats[
node.k])};
1321 for (
size_t i = 0; i < subres.size(); ++i) {
1323 auto& res = subres[subres.size() - i - 1];
1327 std::vector<InputStack> next_sats;
1328 next_sats.push_back(sats[0] + res.nsat);
1329 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + res.nsat) | (std::move(sats[j - 1]) + res.sat));
1330 next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
1332 sats = std::move(next_sats);
1336 InputStack nsat = INVALID;
1337 for (
size_t i = 0; i < sats.size(); ++i) {
1344 if (i != 0 && i !=
node.k) sats[i].SetMalleable().SetNonCanon();
1346 if (i !=
node.k) nsat = std::move(nsat) | std::move(sats[i]);
1349 return {std::move(nsat), std::move(sats[
node.k])};
1352 return {INVALID, ctx.CheckOlder(
node.k) ?
EMPTY : INVALID};
1355 return {INVALID, ctx.CheckAfter(
node.k) ?
EMPTY : INVALID};
1358 std::vector<unsigned char> preimage;
1360 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1363 std::vector<unsigned char> preimage;
1365 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1368 std::vector<unsigned char> preimage;
1370 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1373 std::vector<unsigned char> preimage;
1375 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1378 auto& x = subres[0], &y = subres[1];
1385 return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
1388 auto& x = subres[0], &y = subres[1];
1394 return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
1397 auto& x = subres[0], &z = subres[1];
1399 return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
1402 auto& x = subres[0], &z = subres[1];
1403 return {INVALID, std::move(x.sat) | (z.sat + x.nsat)};
1406 auto& x = subres[0], &z = subres[1];
1407 return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
1410 auto& x = subres[0], &z = subres[1];
1411 return {(x.nsat + ONE) | (z.nsat +
ZERO), (x.sat + ONE) | (z.sat +
ZERO)};
1414 auto& x = subres[0], &y = subres[1], &z = subres[2];
1415 return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
1421 return std::move(subres[0]);
1423 auto &x = subres[0];
1424 return {
ZERO, x.sat + ONE};
1427 auto &x = subres[0];
1433 return {InputStack(
ZERO).SetMalleable(x.nsat.available !=
Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
1436 auto &x = subres[0];
1437 return {INVALID, std::move(x.sat)};
1443 return {INVALID, INVALID};
1446 auto tester = [&helper](
const Node&
node, std::span<InputResult> subres) -> InputResult {
1447 auto ret = helper(
node, subres);
1489 return TreeEval<InputResult>(tester);
1504 Comp(
const Ctx& ctx) : ctx_ptr(&ctx) {}
1505 bool operator()(
const Key& a,
const Key& b)
const {
return ctx_ptr->KeyCompare(a, b); }
1511 using keyset = std::set<Key, Comp>;
1512 using state = std::optional<keyset>;
1514 auto upfn = [&ctx](
const Node&
node, std::span<state> subs) -> state {
1516 if (
node.has_duplicate_keys.has_value() && *
node.has_duplicate_keys)
return {};
1519 for (
auto& sub : subs) {
1520 if (!sub.has_value()) {
1521 node.has_duplicate_keys =
true;
1528 size_t keys_count =
node.keys.size();
1529 keyset key_set{
node.keys.begin(),
node.keys.end(), Comp(ctx)};
1530 if (key_set.size() != keys_count) {
1532 node.has_duplicate_keys =
true;
1537 for (
auto& sub : subs) {
1538 keys_count += sub->size();
1541 if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1542 key_set.merge(*sub);
1543 if (key_set.size() != keys_count) {
1544 node.has_duplicate_keys =
true;
1549 node.has_duplicate_keys =
false;
1553 TreeEval<state>(upfn);
1561 if (!ops.sat.Valid())
return {};
1562 return ops.count + ops.sat.Value();
1577 return !((GetType() &
"BKW"_mst) ==
""_mst);
1582 if (!ss.Sat().Valid())
return {};
1583 return ss.Sat().NetDiff() +
static_cast<int32_t
>(IsBKW());
1588 if (!ss.Sat().Valid())
return {};
1589 return ss.Sat().Exec() +
static_cast<int32_t
>(IsBKW());
1597 if (
const auto exec_ss = GetExecStackSize())
return exec_ss <=
MAX_STACK_SIZE;
1610 if (!ws.sat.Valid())
return {};
1611 return ws.sat.Value();
1622 return TreeEval<const Node*>([](
const Node&
node, std::span<const Node*> subs) ->
const Node* {
1623 for (
auto& sub: subs)
if (sub)
return sub;
1624 if (!
node.IsSaneSubexpression())
return &
node;
1631 template<
typename F>
1635 return TreeEval<int>([&fn](
const Node&
node, std::span<int> subs) ->
bool {
1636 switch (
node.fragment) {
1637 case Fragment::JUST_0:
1639 case Fragment::JUST_1:
1641 case Fragment::PK_K:
1642 case Fragment::PK_H:
1643 case Fragment::MULTI:
1644 case Fragment::MULTI_A:
1645 case Fragment::AFTER:
1646 case Fragment::OLDER:
1647 case Fragment::HASH256:
1648 case Fragment::HASH160:
1649 case Fragment::SHA256:
1650 case Fragment::RIPEMD160:
1651 return bool{fn(node)};
1653 return (subs[0] && subs[1]) || subs[2];
1656 return subs[0] && subs[1];
1661 return subs[0] || subs[1];
1663 return static_cast<uint32_t
>(
std::count(subs.begin(), subs.end(),
true)) >=
node.k;
1665 assert(subs.size() >= 1);
1674 if (GetType() ==
""_mst)
return false;
1697 bool IsSaneSubexpression()
const {
return ValidSatisfactions() && IsNonMalleable() && CheckTimeLocksMix() && CheckDuplicateKey(); }
1700 bool IsSane()
const {
return IsValidTopLevel() && IsSaneSubexpression() && NeedsSignature(); }
1706 template<
typename Ctx>
1707 Availability Satisfy(
const Ctx& ctx, std::vector<std::vector<unsigned char>>& stack,
bool nonmalleable =
true)
const {
1708 auto ret = ProduceInput(ctx);
1709 if (nonmalleable && (
ret.sat.malleable || !
ret.sat.has_sig))
return Availability::NO;
1710 stack = std::move(
ret.sat.stack);
1711 return ret.sat.available;
1719 : 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()) {}
1721 : fragment(nt),
k(val),
data(
std::move(arg)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1723 : 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()) {}
1725 : fragment(nt),
k(val), keys(
std::move(key)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1727 : fragment(nt),
k(val), subs(
std::move(sub)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1729 : fragment(nt),
k(val), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1732 template <
typename Ctx>
Node(
const Ctx& ctx,
enum Fragment nt, std::vector<Node> sub, std::vector<unsigned char> arg, uint32_t val = 0)
1733 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(sub),
std::move(arg), val) { DuplicateKeyCheck(ctx); }
1734 template <
typename Ctx>
Node(
const Ctx& ctx,
enum Fragment nt, std::vector<unsigned char> arg, uint32_t val = 0)
1735 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(arg), val) { DuplicateKeyCheck(ctx);}
1736 template <
typename Ctx>
Node(
const Ctx& ctx,
enum Fragment nt, std::vector<Node> sub, std::vector<Key> key, uint32_t val = 0)
1737 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(sub),
std::move(key), val) { DuplicateKeyCheck(ctx); }
1738 template <
typename Ctx>
Node(
const Ctx& ctx,
enum Fragment nt, std::vector<Key> key, uint32_t val = 0)
1739 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(key), val) { DuplicateKeyCheck(ctx); }
1740 template <
typename Ctx>
Node(
const Ctx& ctx,
enum Fragment nt, std::vector<Node> sub, uint32_t val = 0)
1741 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(sub), val) { DuplicateKeyCheck(ctx); }
1742 template <
typename Ctx>
Node(
const Ctx& ctx,
enum Fragment nt, uint32_t val = 0)
1743 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt, val) { DuplicateKeyCheck(ctx); }
1813template<
typename Key,
typename Ctx>
1814std::optional<Key>
ParseKey(
const std::string& func, std::span<const char>& in,
const Ctx& ctx)
1818 return ctx.FromString(expr);
1822template<
typename Ctx>
1823std::optional<std::vector<unsigned char>>
ParseHexStr(
const std::string& func, std::span<const char>& in,
const size_t expected_size,
1828 std::string val = std::string(expr.begin(), expr.end());
1829 if (!
IsHex(val))
return {};
1831 if (hash.size() != expected_size)
return {};
1836template<
typename Key>
1839 Node<Key> child{std::move(constructed.back())};
1840 constructed.pop_back();
1853template <
typename Key,
typename Ctx>
1854inline std::optional<Node<Key>>
Parse(std::span<const char> in,
const Ctx& ctx)
1868 size_t script_size{1};
1872 std::vector<std::tuple<ParseContext, int64_t, int64_t>> to_parse;
1873 std::vector<Node<Key>> constructed;
1875 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
1878 const auto parse_multi_exp = [&](std::span<const char>& in,
const bool is_multi_a) ->
bool {
1880 const auto required_ctx{is_multi_a ? MiniscriptContext::TAPSCRIPT : MiniscriptContext::P2WSH};
1881 if (ctx.MsContext() != required_ctx)
return false;
1884 if (next_comma < 1)
return false;
1885 const auto k_to_integral{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
1886 if (!k_to_integral.has_value())
return false;
1887 const int64_t
k{k_to_integral.value()};
1888 in = in.subspan(next_comma + 1);
1890 std::vector<Key> keys;
1891 while (next_comma != -1) {
1893 int key_length = (next_comma == -1) ?
FindNextChar(in,
')') : next_comma;
1894 if (key_length < 1)
return false;
1895 std::span<const char> sp{in.begin(), in.begin() + key_length};
1896 auto key = ctx.FromString(sp);
1897 if (!key)
return false;
1898 keys.push_back(std::move(*key));
1899 in = in.subspan(key_length + 1);
1901 if (keys.size() < 1 || keys.size() > max_keys)
return false;
1902 if (k < 1 || k > (int64_t)keys.size())
return false;
1906 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys),
k);
1908 script_size += 2 + (keys.size() > 16) + (
k > 16) + 34 * keys.size();
1909 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys),
k);
1914 while (!to_parse.empty()) {
1915 if (script_size > max_size)
return {};
1918 auto [cur_context, n,
k] = to_parse.back();
1919 to_parse.pop_back();
1921 switch (cur_context) {
1922 case ParseContext::WRAPPED_EXPR: {
1923 std::optional<size_t> colon_index{};
1924 for (
size_t i = 1; i < in.size(); ++i) {
1929 if (in[i] <
'a' || in[i] >
'z')
break;
1932 bool last_was_v{
false};
1933 for (
size_t j = 0; colon_index && j < *colon_index; ++j) {
1934 if (script_size > max_size)
return {};
1937 to_parse.emplace_back(ParseContext::ALT, -1, -1);
1938 }
else if (in[j] ==
's') {
1940 to_parse.emplace_back(ParseContext::SWAP, -1, -1);
1941 }
else if (in[j] ==
'c') {
1944 }
else if (in[j] ==
'd') {
1946 to_parse.emplace_back(ParseContext::DUP_IF, -1, -1);
1947 }
else if (in[j] ==
'j') {
1949 to_parse.emplace_back(ParseContext::NON_ZERO, -1, -1);
1950 }
else if (in[j] ==
'n') {
1952 to_parse.emplace_back(ParseContext::ZERO_NOTEQUAL, -1, -1);
1953 }
else if (in[j] ==
'v') {
1956 if (last_was_v)
return {};
1957 to_parse.emplace_back(ParseContext::VERIFY, -1, -1);
1958 }
else if (in[j] ==
'u') {
1960 to_parse.emplace_back(ParseContext::WRAP_U, -1, -1);
1961 }
else if (in[j] ==
't') {
1963 to_parse.emplace_back(ParseContext::WRAP_T, -1, -1);
1964 }
else if (in[j] ==
'l') {
1968 to_parse.emplace_back(ParseContext::OR_I, -1, -1);
1972 last_was_v = (in[j] ==
'v');
1974 to_parse.emplace_back(ParseContext::EXPR, -1, -1);
1975 if (colon_index) in = in.subspan(*colon_index + 1);
1978 case ParseContext::EXPR: {
1979 if (
Const(
"0", in)) {
1981 }
else if (
Const(
"1", in)) {
1983 }
else if (
Const(
"pk(", in,
false)) {
1984 std::optional<Key> key = ParseKey<Key, Ctx>(
"pk", in, ctx);
1985 if (!key)
return {};
1987 script_size +=
IsTapscript(ctx.MsContext()) ? 33 : 34;
1988 }
else if (
Const(
"pkh(", in,
false)) {
1989 std::optional<Key> key = ParseKey<Key, Ctx>(
"pkh", in, ctx);
1990 if (!key)
return {};
1993 }
else if (
Const(
"pk_k(", in,
false)) {
1994 std::optional<Key> key = ParseKey<Key, Ctx>(
"pk_k", in, ctx);
1995 if (!key)
return {};
1997 script_size +=
IsTapscript(ctx.MsContext()) ? 32 : 33;
1998 }
else if (
Const(
"pk_h(", in,
false)) {
1999 std::optional<Key> key = ParseKey<Key, Ctx>(
"pk_h", in, ctx);
2000 if (!key)
return {};
2003 }
else if (
Const(
"sha256(", in,
false)) {
2004 std::optional<std::vector<unsigned char>> hash =
ParseHexStr(
"sha256", in, 32, ctx);
2005 if (!hash)
return {};
2006 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, std::move(*hash));
2008 }
else if (
Const(
"ripemd160(", in,
false)) {
2009 std::optional<std::vector<unsigned char>> hash =
ParseHexStr(
"ripemd160", in, 20, ctx);
2010 if (!hash)
return {};
2013 }
else if (
Const(
"hash256(", in,
false)) {
2014 std::optional<std::vector<unsigned char>> hash =
ParseHexStr(
"hash256", in, 32, ctx);
2015 if (!hash)
return {};
2016 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, std::move(*hash));
2018 }
else if (
Const(
"hash160(", in,
false)) {
2019 std::optional<std::vector<unsigned char>> hash =
ParseHexStr(
"hash160", in, 20, ctx);
2020 if (!hash)
return {};
2021 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, std::move(*hash));
2023 }
else if (
Const(
"after(", in,
false)) {
2024 auto expr =
Expr(in);
2025 if (!
Func(
"after", expr))
return {};
2026 const auto num{ToIntegral<int64_t>(std::string_view(expr.begin(), expr.end()))};
2027 if (!num.has_value() || *num < 1 || *num >= 0x80000000L)
return {};
2029 script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
2030 }
else if (
Const(
"older(", in,
false)) {
2031 auto expr =
Expr(in);
2032 if (!
Func(
"older", expr))
return {};
2033 const auto num{ToIntegral<int64_t>(std::string_view(expr.begin(), expr.end()))};
2034 if (!num.has_value() || *num < 1 || *num >= 0x80000000L)
return {};
2036 script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
2037 }
else if (
Const(
"multi(", in)) {
2038 if (!parse_multi_exp(in,
false))
return {};
2039 }
else if (
Const(
"multi_a(", in)) {
2040 if (!parse_multi_exp(in,
true))
return {};
2041 }
else if (
Const(
"thresh(", in)) {
2043 if (next_comma < 1)
return {};
2044 const auto k{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
2045 if (!
k.has_value() || *
k < 1)
return {};
2046 in = in.subspan(next_comma + 1);
2048 to_parse.emplace_back(ParseContext::THRESH, 1, *
k);
2049 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2050 script_size += 2 + (*
k > 16) + (*
k > 0x7f) + (*
k > 0x7fff) + (*
k > 0x7fffff);
2051 }
else if (
Const(
"andor(", in)) {
2052 to_parse.emplace_back(ParseContext::ANDOR, -1, -1);
2053 to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
2054 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2055 to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2056 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2057 to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2058 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2061 if (
Const(
"and_n(", in)) {
2062 to_parse.emplace_back(ParseContext::AND_N, -1, -1);
2064 }
else if (
Const(
"and_b(", in)) {
2065 to_parse.emplace_back(ParseContext::AND_B, -1, -1);
2067 }
else if (
Const(
"and_v(", in)) {
2068 to_parse.emplace_back(ParseContext::AND_V, -1, -1);
2070 }
else if (
Const(
"or_b(", in)) {
2071 to_parse.emplace_back(ParseContext::OR_B, -1, -1);
2073 }
else if (
Const(
"or_c(", in)) {
2074 to_parse.emplace_back(ParseContext::OR_C, -1, -1);
2076 }
else if (
Const(
"or_d(", in)) {
2077 to_parse.emplace_back(ParseContext::OR_D, -1, -1);
2079 }
else if (
Const(
"or_i(", in)) {
2080 to_parse.emplace_back(ParseContext::OR_I, -1, -1);
2085 to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
2086 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2087 to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2088 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2092 case ParseContext::ALT: {
2096 case ParseContext::SWAP: {
2104 case ParseContext::DUP_IF: {
2108 case ParseContext::NON_ZERO: {
2112 case ParseContext::ZERO_NOTEQUAL: {
2116 case ParseContext::VERIFY: {
2117 script_size += (constructed.back().GetType() <<
"x"_mst);
2121 case ParseContext::WRAP_U: {
2122 constructed.back() =
Node{
internal::NoDupCheck{}, ctx.MsContext(), Fragment::OR_I,
Vector(std::move(constructed.back()),
Node<Key>{internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0})};
2125 case ParseContext::WRAP_T: {
2126 constructed.back() =
Node{
internal::NoDupCheck{}, ctx.MsContext(), Fragment::AND_V,
Vector(std::move(constructed.back()),
Node<Key>{internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1})};
2129 case ParseContext::AND_B: {
2130 BuildBack(ctx.MsContext(), Fragment::AND_B, constructed);
2133 case ParseContext::AND_N: {
2134 auto mid = std::move(constructed.back());
2135 constructed.pop_back();
2136 constructed.back() =
Node{
internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR,
Vector(std::move(constructed.back()), std::move(mid),
Node<Key>{internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0})};
2139 case ParseContext::AND_V: {
2140 BuildBack(ctx.MsContext(), Fragment::AND_V, constructed);
2143 case ParseContext::OR_B: {
2144 BuildBack(ctx.MsContext(), Fragment::OR_B, constructed);
2147 case ParseContext::OR_C: {
2148 BuildBack(ctx.MsContext(), Fragment::OR_C, constructed);
2151 case ParseContext::OR_D: {
2152 BuildBack(ctx.MsContext(), Fragment::OR_D, constructed);
2155 case ParseContext::OR_I: {
2156 BuildBack(ctx.MsContext(), Fragment::OR_I, constructed);
2159 case ParseContext::ANDOR: {
2160 auto right = std::move(constructed.back());
2161 constructed.pop_back();
2162 auto mid = std::move(constructed.back());
2163 constructed.pop_back();
2164 constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR,
Vector(std::move(constructed.back()), std::move(mid), std::move(right))};
2167 case ParseContext::THRESH: {
2168 if (in.size() < 1)
return {};
2171 to_parse.emplace_back(ParseContext::THRESH, n+1, k);
2172 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2174 }
else if (in[0] ==
')') {
2175 if (k > n)
return {};
2178 std::vector<Node<Key>> subs;
2179 for (
int i = 0; i < n; ++i) {
2180 subs.push_back(std::move(constructed.back()));
2181 constructed.pop_back();
2183 std::reverse(subs.begin(), subs.end());
2184 constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs), k);
2190 case ParseContext::COMMA: {
2191 if (in.size() < 1 || in[0] !=
',')
return {};
2195 case ParseContext::CLOSE_BRACKET: {
2196 if (in.size() < 1 || in[0] !=
')')
return {};
2204 assert(constructed.size() >= 1);
2206 assert(constructed[0].ScriptSize() == script_size);
2207 if (in.size() > 0)
return {};
2208 Node<Key> tl_node{std::move(constructed.front())};
2209 tl_node.DuplicateKeyCheck(ctx);
2295template <
typename Key,
typename Ctx,
typename I>
2299 std::vector<std::tuple<DecodeContext, int64_t, int64_t>> to_parse;
2300 std::vector<Node<Key>> constructed;
2304 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2306 while (!to_parse.empty()) {
2308 if (!constructed.empty() && !constructed.back().IsValid())
return {};
2311 auto [cur_context, n,
k] = to_parse.back();
2312 to_parse.pop_back();
2314 switch(cur_context) {
2315 case DecodeContext::SINGLE_BKV_EXPR: {
2316 if (in >= last)
return {};
2319 if (in[0].first ==
OP_1) {
2324 if (in[0].first ==
OP_0) {
2330 if (in[0].second.size() == 33 || in[0].second.size() == 32) {
2331 auto key = ctx.FromPKBytes(in[0].second.begin(), in[0].second.end());
2332 if (!key)
return {};
2338 auto key = ctx.FromPKHBytes(in[2].second.begin(), in[2].second.end());
2339 if (!key)
return {};
2345 std::optional<int64_t> num;
2348 if (*num < 1 || *num > 0x7FFFFFFFL)
return {};
2354 if (num < 1 || num > 0x7FFFFFFFL)
return {};
2360 if (in[2].first ==
OP_SHA256 && in[1].second.size() == 32) {
2361 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, in[1].second);
2364 }
else if (in[2].first ==
OP_RIPEMD160 && in[1].second.size() == 20) {
2368 }
else if (in[2].first ==
OP_HASH256 && in[1].second.size() == 32) {
2369 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, in[1].second);
2372 }
else if (in[2].first ==
OP_HASH160 && in[1].second.size() == 20) {
2373 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, in[1].second);
2381 std::vector<Key> keys;
2383 if (!n || last - in < 3 + *n)
return {};
2384 if (*n < 1 || *n > 20)
return {};
2385 for (
int i = 0; i < *n; ++i) {
2386 if (in[2 + i].second.size() != 33)
return {};
2387 auto key = ctx.FromPKBytes(in[2 + i].second.begin(), in[2 + i].second.end());
2388 if (!key)
return {};
2389 keys.push_back(std::move(*key));
2392 if (!
k || *k < 1 || *k > *n)
return {};
2394 std::reverse(keys.begin(), keys.end());
2395 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), *
k);
2399 if (last - in >= 4 && in[0].first ==
OP_NUMEQUAL) {
2405 if (last - in < 2 + *
k * 2)
return {};
2406 std::vector<Key> keys;
2409 for (
int pos = 2;; pos += 2) {
2410 if (last - in < pos + 2)
return {};
2413 if (in[pos + 1].second.size() != 32)
return {};
2414 auto key = ctx.FromPKBytes(in[pos + 1].second.begin(), in[pos + 1].second.end());
2415 if (!key)
return {};
2416 keys.push_back(std::move(*key));
2422 if (keys.size() < (
size_t)*
k)
return {};
2423 in += 2 + keys.size() * 2;
2424 std::reverse(keys.begin(), keys.end());
2425 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), *
k);
2435 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2441 to_parse.emplace_back(DecodeContext::VERIFY, -1, -1);
2442 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2448 to_parse.emplace_back(DecodeContext::ZERO_NOTEQUAL, -1, -1);
2449 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2454 if (*num < 1)
return {};
2456 to_parse.emplace_back(DecodeContext::THRESH_W, 0, *num);
2462 to_parse.emplace_back(DecodeContext::ENDIF, -1, -1);
2463 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2474 to_parse.emplace_back(DecodeContext::AND_B, -1, -1);
2475 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2476 to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2482 to_parse.emplace_back(DecodeContext::OR_B, -1, -1);
2483 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2484 to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2490 case DecodeContext::BKV_EXPR: {
2491 to_parse.emplace_back(DecodeContext::MAYBE_AND_V, -1, -1);
2492 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2495 case DecodeContext::W_EXPR: {
2497 if (in >= last)
return {};
2500 to_parse.emplace_back(DecodeContext::ALT, -1, -1);
2502 to_parse.emplace_back(DecodeContext::SWAP, -1, -1);
2504 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2507 case DecodeContext::MAYBE_AND_V: {
2511 to_parse.emplace_back(DecodeContext::AND_V, -1, -1);
2513 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2517 case DecodeContext::SWAP: {
2518 if (in >= last || in[0].first !=
OP_SWAP || constructed.empty())
return {};
2523 case DecodeContext::ALT: {
2524 if (in >= last || in[0].first !=
OP_TOALTSTACK || constructed.empty())
return {};
2530 if (constructed.empty())
return {};
2534 case DecodeContext::DUP_IF: {
2535 if (constructed.empty())
return {};
2539 case DecodeContext::VERIFY: {
2540 if (constructed.empty())
return {};
2544 case DecodeContext::NON_ZERO: {
2545 if (constructed.empty())
return {};
2549 case DecodeContext::ZERO_NOTEQUAL: {
2550 if (constructed.empty())
return {};
2554 case DecodeContext::AND_V: {
2555 if (constructed.size() < 2)
return {};
2556 BuildBack(ctx.MsContext(), Fragment::AND_V, constructed,
true);
2559 case DecodeContext::AND_B: {
2560 if (constructed.size() < 2)
return {};
2561 BuildBack(ctx.MsContext(), Fragment::AND_B, constructed,
true);
2564 case DecodeContext::OR_B: {
2565 if (constructed.size() < 2)
return {};
2566 BuildBack(ctx.MsContext(), Fragment::OR_B, constructed,
true);
2569 case DecodeContext::OR_C: {
2570 if (constructed.size() < 2)
return {};
2571 BuildBack(ctx.MsContext(), Fragment::OR_C, constructed,
true);
2574 case DecodeContext::OR_D: {
2575 if (constructed.size() < 2)
return {};
2576 BuildBack(ctx.MsContext(), Fragment::OR_D, constructed,
true);
2579 case DecodeContext::ANDOR: {
2580 if (constructed.size() < 3)
return {};
2581 Node left{std::move(constructed.back())};
2582 constructed.pop_back();
2583 Node right{std::move(constructed.back())};
2584 constructed.pop_back();
2585 Node mid{std::move(constructed.back())};
2589 case DecodeContext::THRESH_W: {
2590 if (in >= last)
return {};
2591 if (in[0].first ==
OP_ADD) {
2593 to_parse.emplace_back(DecodeContext::THRESH_W, n+1,
k);
2594 to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2596 to_parse.emplace_back(DecodeContext::THRESH_E, n+1,
k);
2598 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2602 case DecodeContext::THRESH_E: {
2603 if (k < 1 || k > n || constructed.size() <
static_cast<size_t>(n))
return {};
2604 std::vector<Node<Key>> subs;
2605 for (
int i = 0; i < n; ++i) {
2606 Node sub{std::move(constructed.back())};
2607 constructed.pop_back();
2608 subs.push_back(std::move(sub));
2610 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs),
k);
2613 case DecodeContext::ENDIF: {
2614 if (in >= last)
return {};
2619 to_parse.emplace_back(DecodeContext::ENDIF_ELSE, -1, -1);
2620 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2623 else if (in[0].first ==
OP_IF) {
2624 if (last - in >= 2 && in[1].first ==
OP_DUP) {
2626 to_parse.emplace_back(DecodeContext::DUP_IF, -1, -1);
2629 to_parse.emplace_back(DecodeContext::NON_ZERO, -1, -1);
2635 }
else if (in[0].first ==
OP_NOTIF) {
2637 to_parse.emplace_back(DecodeContext::ENDIF_NOTIF, -1, -1);
2644 case DecodeContext::ENDIF_NOTIF: {
2645 if (in >= last)
return {};
2648 to_parse.emplace_back(DecodeContext::OR_D, -1, -1);
2650 to_parse.emplace_back(DecodeContext::OR_C, -1, -1);
2653 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2656 case DecodeContext::ENDIF_ELSE: {
2657 if (in >= last)
return {};
2658 if (in[0].first ==
OP_IF) {
2660 BuildBack(ctx.MsContext(), Fragment::OR_I, constructed,
true);
2661 }
else if (in[0].first ==
OP_NOTIF) {
2663 to_parse.emplace_back(DecodeContext::ANDOR, -1, -1);
2665 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2673 if (constructed.size() != 1)
return {};
2674 Node tl_node{std::move(constructed.front())};
2678 if (!tl_node.IsValidTopLevel())
return {};
2684template <
typename Ctx>
2685inline std::optional<Node<typename Ctx::Key>>
FromString(
const std::string& str,
const Ctx& ctx)
2687 return internal::Parse<typename Ctx::Key>(str, ctx);
2690template <
typename Ctx>
2693 using namespace internal;
2697 if (!decomposed)
return {};
2698 auto it = decomposed->begin();
2699 auto ret = DecodeScript<typename Ctx::Key>(it, decomposed->end(), ctx);
2700 if (!
ret)
return {};
2701 if (it != decomposed->end())
return {};
#define CHECK_NONFATAL(condition)
Identity function.
Serialized script, used inside transaction inputs and outputs.
A node in a miniscript expression.
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 std::vector< Key > & Keys() const
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.
Node(internal::NoDupCheck, MiniscriptContext script_ctx, enum Fragment nt, std::vector< Node > sub, uint32_t val=0)
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.
Type typ
Cached expression type (computed by CalcType and fed through SanitizeType).
std::vector< unsigned char > data
The data bytes in this expression (only for HASH160/HASH256/SHA256/RIPEMD160).
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.
enum Fragment Fragment() const
const std::vector< unsigned char > & Data() const
Node(internal::NoDupCheck, MiniscriptContext script_ctx, enum Fragment nt, std::vector< Node > sub, std::vector< unsigned char > arg, uint32_t val=0)
friend int Compare(const Node< Key > &node1, const Node< Key > &node2)
Compare two miniscript subtrees, using a non-recursive algorithm.
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.
std::optional< uint32_t > GetExecStackSize() const
Return the maximum size of the stack during execution of this script.
Node(internal::NoDupCheck, MiniscriptContext script_ctx, enum Fragment nt, std::vector< Key > key, uint32_t val=0)
bool NeedsSignature() const
Check whether this script always needs a signature.
std::vector< Node > subs
Subexpressions (for WRAP_*/AND_*/OR_*/ANDOR/THRESH)
std::optional< std::string > ToString(const CTx &ctx, bool &has_priv_key) const
internal::WitnessSize ws
Cached witness size bounds.
bool CheckOpsLimit() const
Check the ops limit of this script against the consensus limit.
std::vector< Key > keys
The keys used by this expression (only for PK_K/PK_H/MULTI)
std::optional< uint32_t > GetWitnessSize() const
Return the maximum size in bytes of a witness to satisfy this script non-malleably.
Node(const Node &)=delete
uint32_t k
The k parameter (time for OLDER/AFTER, threshold for THRESH(_M))
Node< Key > Clone() const
Node(const Ctx &ctx, enum Fragment nt, std::vector< Node > sub, std::vector< unsigned char > arg, uint32_t val=0)
std::optional< Result > TreeEvalMaybe(UpFn upfn) const
Like TreeEvalMaybe, but without downfn or State type.
internal::WitnessSize CalcWitnessSize() const
Node(Node &&) noexcept=default
Result TreeEval(State root_state, DownFn &&downfn, UpFn upfn) const
Like TreeEvalMaybe, but always produces a result.
internal::Ops CalcOps() const
internal::StackSize ss
Cached stack size bounds.
Node(internal::NoDupCheck, MiniscriptContext script_ctx, enum Fragment nt, std::vector< Node > sub, std::vector< Key > key, std::vector< unsigned char > arg, uint32_t val)
std::optional< std::string > ToString(const CTx &ctx) const
const std::vector< Node > & Subs() const
Node(const Ctx &ctx, enum Fragment nt, std::vector< Key > key, uint32_t val=0)
size_t CalcScriptLen() const
Compute the length of the script for this miniscript (including children).
Node(internal::NoDupCheck, MiniscriptContext script_ctx, enum Fragment nt, std::vector< Node > sub, std::vector< Key > key, uint32_t val=0)
Node(internal::NoDupCheck, MiniscriptContext script_ctx, enum Fragment nt, uint32_t val=0)
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.
enum Fragment fragment
What node type this node is.
Node(const Ctx &ctx, enum Fragment nt, std::vector< Node > sub, std::vector< Key > key, uint32_t val=0)
bool IsNotSatisfiable() const
Whether no satisfaction exists for this node.
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.
size_t ScriptSize() const
Return the size of the script for this expression (faster than ToScript().size()).
MiniscriptContext m_script_ctx
The Script context for this node. Either P2WSH or Tapscript.
bool ValidSatisfactions() const
Whether successful non-malleable satisfactions are guaranteed to be valid.
void DuplicateKeyCheck(const Ctx &ctx) const
Update duplicate key information in this Node.
Node(const Ctx &ctx, enum Fragment nt, std::vector< unsigned char > arg, uint32_t val=0)
bool operator==(const Node< Key > &arg) const
Equality testing.
Node(const Ctx &ctx, enum Fragment nt, std::vector< Node > sub, 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.
internal::Ops ops
Cached ops counts.
MiniscriptContext GetMsCtx() const
Return the script context for this node.
size_t scriptlen
Cached script length (computed by CalcScriptLen).
bool IsValid() const
Check whether this node is valid at all.
Node(const Ctx &ctx, enum Fragment nt, uint32_t val=0)
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, enum Fragment nt, std::vector< unsigned char > arg, uint32_t val=0)
bool IsSatisfiable(F fn) const
Determine whether a Miniscript node is satisfiable.
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.
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)
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).
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.
int32_t exec
How much higher the stack size can be during execution 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
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.
bool valid
Whether a canonical satisfaction/dissatisfaction is possible at all.
int32_t netdiff
How much higher the stack size at start of execution can be compared to at the end.
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
const SatInfo & Dsat() const
constexpr StackSize(SatInfo in_sat, SatInfo in_dsat) noexcept
const SatInfo & Sat() const
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< Node< Key > > Parse(std::span< const char > in, const Ctx &ctx)
Parse a miniscript from its textual descriptor form.
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.
constexpr uint32_t TX_BODY_LEEWAY_WEIGHT
Data other than the witness in a transaction. Overhead + vin count + one vin + vout count + one vout ...
std::optional< Node< Key > > DecodeScript(I &in, I last, const Ctx &ctx)
Parse a miniscript from a bitcoin script.
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...
std::optional< Key > ParseKey(const std::string &func, std::span< const char > &in, const Ctx &ctx)
Parse a key expression fully contained within a fragment with the name given by 'func'.
std::optional< std::vector< unsigned char > > ParseHexStr(const std::string &func, std::span< const char > &in, const size_t expected_size, const Ctx &ctx)
Parse a hex string fully contained within a fragment with the name given by 'func'.
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.
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< Node< 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...
constexpr bool IsTapscript(MiniscriptContext ms_ctx)
Whether the context Tapscript, ensuring the only other possibility is P2WSH.
std::optional< Node< typename Ctx::Key > > FromScript(const CScript &script, const Ctx &ctx)
void ForEachNode(const Node< Key > &root, Fn &&fn)
Unordered traversal of a miniscript node tree.
std::optional< Node< typename Ctx::Key > > FromString(const std::string &str, const Ctx &ctx)
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)
std::span< const char > Expr(std::span< const char > &sp)
Extract the expression that sp begins with.
bool Func(const std::string &str, std::span< const char > &sp)
Parse a function call.
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.
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.
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.