5#ifndef BITCOIN_SCRIPT_MINISCRIPT_H
6#define BITCOIN_SCRIPT_MINISCRIPT_H
139 friend consteval Type operator""_mst(
const char* c,
size_t l);
161inline consteval Type operator""_mst(
const char* c,
size_t l)
165 for (
const char *p = c; p < c + l; p++) {
177 *p ==
'f' ? 1 << 10 :
178 *p ==
's' ? 1 << 11 :
179 *p ==
'm' ? 1 << 12 :
180 *p ==
'x' ? 1 << 13 :
181 *p ==
'g' ? 1 << 14 :
182 *p ==
'h' ? 1 << 15 :
183 *p ==
'i' ? 1 << 16 :
184 *p ==
'j' ? 1 << 17 :
185 *p ==
'k' ? 1 << 18 :
186 (
throw std::logic_error(
"Unknown character in _mst literal"), 0)
193using Opcode = std::pair<opcodetype, std::vector<unsigned char>>;
195template<
typename Key>
class Node;
198template <
typename Key, std::invocable<const Node<Key>&> Fn>
201 std::vector<std::reference_wrapper<const Node<Key>>> stack{root};
202 while (!stack.empty()) {
204 std::invoke(fn,
node);
206 for (
const auto& sub :
node.Subs()) {
207 stack.emplace_back(sub);
325 std::vector<std::vector<unsigned char>>
stack;
359 template<
typename A,
typename B>
383 if (!a.
valid)
return b;
384 if (!b.
valid)
return a;
455 constexpr SatInfo(int32_t in_netdiff, int32_t in_exec) noexcept :
466 if (!a.valid)
return b;
467 if (!b.valid)
return a;
469 return {std::max(a.netdiff, b.netdiff), std::max(a.exec, b.exec)};
476 if (!a.valid || !b.valid)
return {};
480 return {a.
netdiff + b.netdiff, std::max(b.exec, b.netdiff + a.exec)};
492 static constexpr SatInfo If() noexcept {
return {1, 1}; }
498 static constexpr SatInfo OP_IFDUP(
bool nonzero)
noexcept {
return {nonzero ? -1 : 0, 0}; }
533template <
typename Key>
543 std::vector<unsigned char>
data;
560 std::vector<std::vector<Node>> queue;
561 queue.push_back(std::move(
subs));
563 auto flattening{std::move(queue.back())};
565 for (
Node& n : flattening) {
566 if (!n.subs.empty()) queue.push_back(std::move(n.subs));
568 }
while (!queue.empty());
575 auto upfn = [](
const Node&
node, std::span<Node> children) {
576 std::vector<Node> new_subs;
577 for (
auto& child : children) {
580 new_subs.push_back(std::move(child));
584 return TreeEval<Node>(upfn);
588 uint32_t
K()
const {
return k; }
589 const std::vector<Key>&
Keys()
const {
return keys; }
590 const std::vector<unsigned char>&
Data()
const {
return data; }
591 const std::vector<Node>&
Subs()
const {
return subs; }
615 :
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()) {}
621 for (
const auto& sub :
subs) {
622 subsize += sub.ScriptSize();
624 Type sub0type =
subs.size() > 0 ?
subs[0].GetType() :
""_mst;
651 template<
typename Result,
typename State,
typename DownFn,
typename UpFn>
661 StackElem(
const Node& node_,
size_t exp_,
State&& state_) :
662 node(node_), expanded(exp_), state(std::move(state_)) {}
665 std::vector<StackElem> stack;
668 std::vector<Result> results;
669 stack.emplace_back(*
this, 0, std::move(root_state));
687 while (stack.size()) {
688 const Node&
node = stack.back().node;
689 if (stack.back().expanded <
node.subs.size()) {
693 size_t child_index = stack.back().expanded++;
694 State child_state = downfn(stack.back().state,
node, child_index);
695 stack.emplace_back(
node.subs[child_index], 0, std::move(child_state));
700 std::optional<Result> result{upfn(std::move(stack.back().state),
node,
701 std::span<Result>{results}.last(
node.subs.size()))};
703 if (!result)
return {};
705 results.erase(results.end() -
node.subs.size(), results.end());
706 results.push_back(std::move(*result));
710 assert(results.size() >= 1);
712 return std::move(results[0]);
717 template<
typename Result,
typename UpFn>
720 struct DummyState {};
721 return TreeEvalMaybe<Result>(DummyState{},
722 [](DummyState,
const Node&, size_t) {
return DummyState{}; },
723 [&upfn](DummyState,
const Node&
node, std::span<Result>
subs) {
730 template<
typename Result,
typename State,
typename DownFn,
typename UpFn>
735 return std::move(*TreeEvalMaybe<Result>(std::move(root_state),
736 std::forward<DownFn>(downfn),
739 return std::optional<Result>(std::move(res));
746 template<
typename Result,
typename UpFn>
749 struct DummyState {};
750 return std::move(*TreeEvalMaybe<Result>(DummyState{},
751 [](DummyState,
const Node&, size_t) {
return DummyState{}; },
752 [&upfn](DummyState,
const Node&
node, std::span<Result>
subs) {
754 return std::optional<Result>(std::move(res));
762 std::vector<std::pair<const Node<Key>&,
const Node<Key>&>> queue;
763 queue.emplace_back(node1, node2);
764 while (!queue.empty()) {
765 const auto& [a, b] = queue.back();
767 if (std::tie(a.fragment, a.k, a.keys, a.data) < std::tie(b.fragment, b.k, b.keys, b.data))
return -1;
768 if (std::tie(b.fragment, b.k, b.keys, b.data) < std::tie(a.fragment, a.k, a.keys, a.data))
return 1;
769 if (a.subs.size() < b.subs.size())
return -1;
770 if (b.subs.size() < a.subs.size())
return 1;
771 size_t n = a.
subs.size();
772 for (
size_t i = 0; i < n; ++i) {
773 queue.emplace_back(a.subs[n - 1 - i], b.subs[n - 1 - i]);
781 using namespace internal;
784 std::vector<Type> sub_types;
786 for (
const auto& sub :
subs) sub_types.push_back(sub.GetType());
797 template<
typename Ctx>
816 switch (
node.fragment) {
830 if (
node.subs[0].GetType() <<
"x"_mst) {
833 return std::move(
subs[0]);
850 for (
const auto& key :
node.keys) {
858 for (
auto it =
node.keys.begin() + 1; it !=
node.keys.end(); ++it) {
865 for (
size_t i = 1; i <
subs.size(); ++i) {
873 return TreeEval<CScript>(
false, downfn, upfn);
876 template<
typename CTx>
877 std::optional<std::string>
ToString(
const CTx& ctx)
const {
882 template<
typename CTx>
883 std::optional<std::string>
ToString(
const CTx& ctx,
bool& has_priv_key)
const {
887 auto downfn = [](bool,
const Node&
node, size_t) {
896 auto toString = [&ctx, &has_priv_key](Key key) -> std::optional<std::string> {
897 bool fragment_has_priv_key{
false};
898 auto key_str{ctx.ToString(key, fragment_has_priv_key)};
899 if (key_str) has_priv_key = has_priv_key || fragment_has_priv_key;
905 auto upfn = [is_tapscript, &toString](
bool wrapped,
const Node&
node, std::span<std::string>
subs) -> std::optional<std::string> {
906 std::string
ret = wrapped ?
":" :
"";
908 switch (
node.fragment) {
914 auto key_str = toString(
node.subs[0].keys[0]);
915 if (!key_str)
return {};
916 return std::move(
ret) +
"pk(" + std::move(*key_str) +
")";
920 auto key_str = toString(
node.subs[0].keys[0]);
921 if (!key_str)
return {};
922 return std::move(
ret) +
"pkh(" + std::move(*key_str) +
")";
924 return "c" + std::move(
subs[0]);
939 switch (
node.fragment) {
941 auto key_str = toString(
node.keys[0]);
942 if (!key_str)
return {};
943 return std::move(
ret) +
"pk_k(" + std::move(*key_str) +
")";
946 auto key_str = toString(
node.keys[0]);
947 if (!key_str)
return {};
948 return std::move(
ret) +
"pk_h(" + std::move(*key_str) +
")";
967 return std::move(
ret) +
"andor(" + std::move(
subs[0]) +
"," + std::move(
subs[1]) +
"," + std::move(
subs[2]) +
")";
971 for (
const auto& key :
node.keys) {
972 auto key_str = toString(key);
973 if (!key_str)
return {};
974 str +=
"," + std::move(*key_str);
976 return std::move(str) +
")";
981 for (
const auto& key :
node.keys) {
982 auto key_str = toString(key);
983 if (!key_str)
return {};
984 str +=
"," + std::move(*key_str);
986 return std::move(str) +
")";
990 for (
auto& sub :
subs) {
991 str +=
"," + std::move(sub);
993 return std::move(str) +
")";
1000 return TreeEvalMaybe<std::string>(
false, downfn, upfn);
1018 const auto count{1 +
subs[0].ops.count +
subs[1].ops.count};
1019 const auto sat{
subs[0].ops.sat +
subs[1].ops.sat};
1020 const auto dsat{
subs[0].ops.dsat +
subs[1].ops.dsat};
1021 return {
count, sat, dsat};
1024 const auto count{1 +
subs[0].ops.count +
subs[1].ops.count};
1026 const auto dsat{
subs[0].ops.dsat +
subs[1].ops.dsat};
1027 return {
count, sat, dsat};
1030 const auto count{3 +
subs[0].ops.count +
subs[1].ops.count};
1031 const auto sat{
subs[0].ops.sat | (
subs[1].ops.sat +
subs[0].ops.dsat)};
1032 const auto dsat{
subs[0].ops.dsat +
subs[1].ops.dsat};
1033 return {
count, sat, dsat};
1036 const auto count{2 +
subs[0].ops.count +
subs[1].ops.count};
1037 const auto sat{
subs[0].ops.sat | (
subs[1].ops.sat +
subs[0].ops.dsat)};
1038 return {
count, sat, {}};
1041 const auto count{3 +
subs[0].ops.count +
subs[1].ops.count};
1042 const auto sat{
subs[0].ops.sat |
subs[1].ops.sat};
1043 const auto dsat{
subs[0].ops.dsat |
subs[1].ops.dsat};
1044 return {
count, sat, dsat};
1047 const auto count{3 +
subs[0].ops.count +
subs[1].ops.count +
subs[2].ops.count};
1049 const auto dsat{
subs[0].ops.dsat +
subs[2].ops.dsat};
1050 return {
count, sat, dsat};
1064 for (
const auto& sub :
subs) {
1065 count += sub.ops.count + 1;
1066 auto next_sats =
Vector(sats[0] + sub.ops.dsat);
1067 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub.ops.dsat) | (sats[j - 1] + sub.ops.sat));
1068 next_sats.push_back(sats[sats.size() - 1] + sub.ops.sat);
1069 sats = std::move(next_sats);
1072 return {
count, sats[
k], sats[0]};
1079 using namespace internal;
1095 const auto& x{subs[0].ss};
1096 const auto& y{subs[1].ss};
1097 const auto& z{subs[2].ss};
1099 (x.Sat() + SatInfo::If() + y.Sat()) | (x.Dsat() + SatInfo::If() + z.Sat()),
1100 x.Dsat() + SatInfo::If() + z.Dsat()
1104 const auto& x{subs[0].ss};
1105 const auto& y{subs[1].ss};
1106 return {x.Sat() + y.Sat(), {}};
1109 const auto& x{subs[0].ss};
1110 const auto& y{subs[1].ss};
1111 return {x.Sat() + y.Sat() + SatInfo::BinaryOp(), x.Dsat() + y.Dsat() + SatInfo::BinaryOp()};
1114 const auto& x{subs[0].ss};
1115 const auto& y{subs[1].ss};
1117 ((x.Sat() + y.Dsat()) | (x.Dsat() + y.Sat())) + SatInfo::BinaryOp(),
1118 x.Dsat() + y.Dsat() + SatInfo::BinaryOp()
1122 const auto& x{subs[0].ss};
1123 const auto& y{subs[1].ss};
1124 return {(x.Sat() + SatInfo::If()) | (x.Dsat() + SatInfo::If() + y.Sat()), {}};
1127 const auto& x{subs[0].ss};
1128 const auto& y{subs[1].ss};
1135 const auto& x{subs[0].ss};
1136 const auto& y{subs[1].ss};
1137 return {SatInfo::If() + (x.Sat() | y.Sat()), SatInfo::If() + (x.Dsat() | y.Dsat())};
1166 auto sats =
Vector(SatInfo::Empty());
1167 for (
size_t i = 0; i < subs.size(); ++i) {
1170 auto add = i ? SatInfo::BinaryOp() : SatInfo::Empty();
1172 auto next_sats =
Vector(sats[0] + subs[i].ss.Dsat() + add);
1174 for (
size_t j = 1; j < sats.size(); ++j) {
1175 next_sats.push_back(((sats[j] + subs[i].ss.Dsat()) | (sats[j - 1] + subs[i].ss.Sat())) + add);
1178 next_sats.push_back(sats[sats.size() - 1] + subs[i].ss.Sat() + add);
1180 sats = std::move(next_sats);
1195 const uint32_t pubkey_size =
IsTapscript(m_script_ctx) ? 1 + 32 : 1 + 33;
1208 const auto sat{(subs[0].ws.sat + subs[1].ws.sat) | (subs[0].ws.dsat + subs[2].ws.sat)};
1209 const auto dsat{subs[0].ws.dsat + subs[2].ws.dsat};
1213 case Fragment::AND_B:
return {subs[0].ws.sat + subs[1].ws.sat, subs[0].ws.dsat + subs[1].ws.dsat};
1215 const auto sat{(subs[0].ws.dsat + subs[1].ws.sat) | (subs[0].ws.sat + subs[1].ws.dsat)};
1216 const auto dsat{subs[0].ws.dsat + subs[1].ws.dsat};
1219 case Fragment::OR_C:
return {subs[0].ws.sat | (subs[0].ws.dsat + subs[1].ws.sat), {}};
1220 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};
1221 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)};
1233 for (
const auto& sub : subs) {
1234 auto next_sats =
Vector(sats[0] + sub.ws.dsat);
1235 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub.ws.dsat) | (sats[j - 1] + sub.ws.sat));
1236 next_sats.push_back(sats[sats.size() - 1] + sub.ws.sat);
1237 sats = std::move(next_sats);
1240 return {sats[
k], sats[0]};
1246 template<
typename Ctx>
1248 using namespace internal;
1252 auto helper = [&ctx](
const Node&
node, std::span<InputResult> subres) -> InputResult {
1253 switch (
node.fragment) {
1255 std::vector<unsigned char> sig;
1257 return {
ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
1260 std::vector<unsigned char> key = ctx.ToPKBytes(
node.keys[0]), sig;
1262 return {
ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
1268 for (
size_t i = 0; i <
node.keys.size(); ++i) {
1271 std::vector<unsigned char> sig;
1274 auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1278 std::vector<InputStack> next_sats;
1279 next_sats.push_back(sats[0] +
ZERO);
1280 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] +
ZERO) | (std::move(sats[j - 1]) + sat));
1281 next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1283 sats = std::move(next_sats);
1287 auto& nsat{sats[0]};
1290 return {std::move(nsat), std::move(sats[
node.k])};
1297 for (
size_t i = 0; i <
node.keys.size(); ++i) {
1298 std::vector<unsigned char> sig;
1301 auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1305 std::vector<InputStack> next_sats;
1306 next_sats.push_back(sats[0]);
1307 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
1308 next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1310 sats = std::move(next_sats);
1313 InputStack nsat =
ZERO;
1314 for (
size_t i = 0; i <
node.k; ++i) nsat = std::move(nsat) +
ZERO;
1316 return {std::move(nsat), std::move(sats[
node.k])};
1323 for (
size_t i = 0; i < subres.size(); ++i) {
1325 auto& res = subres[subres.size() - i - 1];
1329 std::vector<InputStack> next_sats;
1330 next_sats.push_back(sats[0] + res.nsat);
1331 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + res.nsat) | (std::move(sats[j - 1]) + res.sat));
1332 next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
1334 sats = std::move(next_sats);
1338 InputStack nsat = INVALID;
1339 for (
size_t i = 0; i < sats.size(); ++i) {
1346 if (i != 0 && i !=
node.k) sats[i].SetMalleable().SetNonCanon();
1348 if (i !=
node.k) nsat = std::move(nsat) | std::move(sats[i]);
1351 return {std::move(nsat), std::move(sats[
node.k])};
1354 return {INVALID, ctx.CheckOlder(
node.k) ?
EMPTY : INVALID};
1357 return {INVALID, ctx.CheckAfter(
node.k) ?
EMPTY : INVALID};
1360 std::vector<unsigned char> preimage;
1362 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1365 std::vector<unsigned char> preimage;
1367 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1370 std::vector<unsigned char> preimage;
1372 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1375 std::vector<unsigned char> preimage;
1377 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1380 auto& x = subres[0], &y = subres[1];
1387 return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
1390 auto& x = subres[0], &y = subres[1];
1396 return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
1399 auto& x = subres[0], &z = subres[1];
1401 return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
1404 auto& x = subres[0], &z = subres[1];
1405 return {INVALID, std::move(x.sat) | (z.sat + x.nsat)};
1408 auto& x = subres[0], &z = subres[1];
1409 return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
1412 auto& x = subres[0], &z = subres[1];
1413 return {(x.nsat + ONE) | (z.nsat +
ZERO), (x.sat + ONE) | (z.sat +
ZERO)};
1416 auto& x = subres[0], &y = subres[1], &z = subres[2];
1417 return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
1423 return std::move(subres[0]);
1425 auto &x = subres[0];
1426 return {
ZERO, x.sat + ONE};
1429 auto &x = subres[0];
1435 return {InputStack(
ZERO).SetMalleable(x.nsat.available !=
Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
1438 auto &x = subres[0];
1439 return {INVALID, std::move(x.sat)};
1445 return {INVALID, INVALID};
1448 auto tester = [&helper](
const Node&
node, std::span<InputResult> subres) -> InputResult {
1449 auto ret = helper(
node, subres);
1491 return TreeEval<InputResult>(tester);
1506 Comp(
const Ctx& ctx) : ctx_ptr(&ctx) {}
1507 bool operator()(
const Key& a,
const Key& b)
const {
return ctx_ptr->KeyCompare(a, b); }
1513 using keyset = std::set<Key, Comp>;
1514 using state = std::optional<keyset>;
1516 auto upfn = [&ctx](
const Node&
node, std::span<state> subs) -> state {
1518 if (
node.has_duplicate_keys.has_value() && *
node.has_duplicate_keys)
return {};
1521 for (
auto& sub : subs) {
1522 if (!sub.has_value()) {
1523 node.has_duplicate_keys =
true;
1530 size_t keys_count =
node.keys.size();
1531 keyset key_set{
node.keys.begin(),
node.keys.end(), Comp(ctx)};
1532 if (key_set.size() != keys_count) {
1534 node.has_duplicate_keys =
true;
1539 for (
auto& sub : subs) {
1540 keys_count += sub->size();
1543 if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1544 key_set.merge(*sub);
1545 if (key_set.size() != keys_count) {
1546 node.has_duplicate_keys =
true;
1551 node.has_duplicate_keys =
false;
1555 TreeEval<state>(upfn);
1563 if (!ops.sat.Valid())
return {};
1564 return ops.count + ops.sat.Value();
1579 return !((GetType() &
"BKW"_mst) ==
""_mst);
1584 if (!ss.Sat().Valid())
return {};
1585 return ss.Sat().NetDiff() +
static_cast<int32_t
>(IsBKW());
1590 if (!ss.Sat().Valid())
return {};
1591 return ss.Sat().Exec() +
static_cast<int32_t
>(IsBKW());
1599 if (
const auto exec_ss = GetExecStackSize())
return exec_ss <=
MAX_STACK_SIZE;
1612 if (!ws.sat.Valid())
return {};
1613 return ws.sat.Value();
1624 return TreeEval<const Node*>([](
const Node&
node, std::span<const Node*> subs) ->
const Node* {
1625 for (
auto& sub: subs)
if (sub)
return sub;
1626 if (!
node.IsSaneSubexpression())
return &
node;
1633 template<
typename F>
1637 return TreeEval<int>([&fn](
const Node&
node, std::span<int> subs) ->
bool {
1638 switch (
node.fragment) {
1639 case Fragment::JUST_0:
1641 case Fragment::JUST_1:
1643 case Fragment::PK_K:
1644 case Fragment::PK_H:
1645 case Fragment::MULTI:
1646 case Fragment::MULTI_A:
1647 case Fragment::AFTER:
1648 case Fragment::OLDER:
1649 case Fragment::HASH256:
1650 case Fragment::HASH160:
1651 case Fragment::SHA256:
1652 case Fragment::RIPEMD160:
1653 return bool{fn(node)};
1655 return (subs[0] && subs[1]) || subs[2];
1658 return subs[0] && subs[1];
1663 return subs[0] || subs[1];
1665 return static_cast<uint32_t
>(
std::count(subs.begin(), subs.end(),
true)) >=
node.k;
1667 assert(subs.size() >= 1);
1676 if (GetType() ==
""_mst)
return false;
1699 bool IsSaneSubexpression()
const {
return ValidSatisfactions() && IsNonMalleable() && CheckTimeLocksMix() && CheckDuplicateKey(); }
1702 bool IsSane()
const {
return IsValidTopLevel() && IsSaneSubexpression() && NeedsSignature(); }
1708 template<
typename Ctx>
1709 Availability Satisfy(
const Ctx& ctx, std::vector<std::vector<unsigned char>>& stack,
bool nonmalleable =
true)
const {
1710 auto ret = ProduceInput(ctx);
1711 if (nonmalleable && (
ret.sat.malleable || !
ret.sat.has_sig))
return Availability::NO;
1712 stack = std::move(
ret.sat.stack);
1713 return ret.sat.available;
1721 : 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()) {}
1723 : fragment(nt),
k(val),
data(
std::move(arg)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1725 : 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()) {}
1727 : fragment(nt),
k(val),
keys(
std::move(key)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1729 : fragment(nt),
k(val), subs(
std::move(sub)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1731 : fragment(nt),
k(val), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1734 template <
typename Ctx>
Node(
const Ctx& ctx,
enum Fragment nt, std::vector<Node> sub, std::vector<unsigned char> arg, uint32_t val = 0)
1735 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(sub),
std::move(arg), val) { DuplicateKeyCheck(ctx); }
1736 template <
typename Ctx>
Node(
const Ctx& ctx,
enum Fragment nt, std::vector<unsigned char> arg, uint32_t val = 0)
1737 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(arg), val) { DuplicateKeyCheck(ctx);}
1738 template <
typename Ctx>
Node(
const Ctx& ctx,
enum Fragment nt, std::vector<Node> sub, std::vector<Key> key, uint32_t val = 0)
1739 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(sub),
std::move(key), val) { DuplicateKeyCheck(ctx); }
1740 template <
typename Ctx>
Node(
const Ctx& ctx,
enum Fragment nt, std::vector<Key> key, uint32_t val = 0)
1741 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(key), val) { DuplicateKeyCheck(ctx); }
1742 template <
typename Ctx>
Node(
const Ctx& ctx,
enum Fragment nt, std::vector<Node> sub, uint32_t val = 0)
1743 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(sub), val) { DuplicateKeyCheck(ctx); }
1744 template <
typename Ctx>
Node(
const Ctx& ctx,
enum Fragment nt, uint32_t val = 0)
1745 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt, val) { DuplicateKeyCheck(ctx); }
1815template<
typename Key,
typename Ctx>
1816std::optional<Key>
ParseKey(
const std::string& func, std::span<const char>& in,
const Ctx& ctx)
1820 return ctx.FromString(expr);
1824template<
typename Ctx>
1825std::optional<std::vector<unsigned char>>
ParseHexStr(
const std::string& func, std::span<const char>& in,
const size_t expected_size,
1830 std::string val = std::string(expr.begin(), expr.end());
1831 if (!
IsHex(val))
return {};
1833 if (hash.size() != expected_size)
return {};
1838template<
typename Key>
1841 Node<Key> child{std::move(constructed.back())};
1842 constructed.pop_back();
1855template <
typename Key,
typename Ctx>
1856inline std::optional<Node<Key>>
Parse(std::span<const char> in,
const Ctx& ctx)
1870 size_t script_size{1};
1874 std::vector<std::tuple<ParseContext, int64_t, int64_t>> to_parse;
1875 std::vector<Node<Key>> constructed;
1877 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
1880 const auto parse_multi_exp = [&](std::span<const char>& in,
const bool is_multi_a) ->
bool {
1882 const auto required_ctx{is_multi_a ? MiniscriptContext::TAPSCRIPT : MiniscriptContext::P2WSH};
1883 if (ctx.MsContext() != required_ctx)
return false;
1886 if (next_comma < 1)
return false;
1887 const auto k_to_integral{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
1888 if (!k_to_integral.has_value())
return false;
1889 const int64_t
k{k_to_integral.value()};
1890 in = in.subspan(next_comma + 1);
1892 std::vector<Key>
keys;
1893 while (next_comma != -1) {
1895 int key_length = (next_comma == -1) ?
FindNextChar(in,
')') : next_comma;
1896 if (key_length < 1)
return false;
1897 std::span<const char> sp{in.begin(), in.begin() + key_length};
1898 auto key = ctx.FromString(sp);
1899 if (!key)
return false;
1900 keys.push_back(std::move(*key));
1901 in = in.subspan(key_length + 1);
1903 if (
keys.size() < 1 ||
keys.size() > max_keys)
return false;
1904 if (k < 1 || k > (int64_t)
keys.size())
return false;
1910 script_size += 2 + (
keys.size() > 16) + (
k > 16) + 34 *
keys.size();
1916 while (!to_parse.empty()) {
1917 if (script_size > max_size)
return {};
1920 auto [cur_context, n,
k] = to_parse.back();
1921 to_parse.pop_back();
1923 switch (cur_context) {
1924 case ParseContext::WRAPPED_EXPR: {
1925 std::optional<size_t> colon_index{};
1926 for (
size_t i = 1; i < in.size(); ++i) {
1931 if (in[i] <
'a' || in[i] >
'z')
break;
1934 bool last_was_v{
false};
1935 for (
size_t j = 0; colon_index && j < *colon_index; ++j) {
1936 if (script_size > max_size)
return {};
1939 to_parse.emplace_back(ParseContext::ALT, -1, -1);
1940 }
else if (in[j] ==
's') {
1942 to_parse.emplace_back(ParseContext::SWAP, -1, -1);
1943 }
else if (in[j] ==
'c') {
1946 }
else if (in[j] ==
'd') {
1948 to_parse.emplace_back(ParseContext::DUP_IF, -1, -1);
1949 }
else if (in[j] ==
'j') {
1951 to_parse.emplace_back(ParseContext::NON_ZERO, -1, -1);
1952 }
else if (in[j] ==
'n') {
1954 to_parse.emplace_back(ParseContext::ZERO_NOTEQUAL, -1, -1);
1955 }
else if (in[j] ==
'v') {
1958 if (last_was_v)
return {};
1959 to_parse.emplace_back(ParseContext::VERIFY, -1, -1);
1960 }
else if (in[j] ==
'u') {
1962 to_parse.emplace_back(ParseContext::WRAP_U, -1, -1);
1963 }
else if (in[j] ==
't') {
1965 to_parse.emplace_back(ParseContext::WRAP_T, -1, -1);
1966 }
else if (in[j] ==
'l') {
1970 to_parse.emplace_back(ParseContext::OR_I, -1, -1);
1974 last_was_v = (in[j] ==
'v');
1976 to_parse.emplace_back(ParseContext::EXPR, -1, -1);
1977 if (colon_index) in = in.subspan(*colon_index + 1);
1980 case ParseContext::EXPR: {
1981 if (
Const(
"0", in)) {
1983 }
else if (
Const(
"1", in)) {
1985 }
else if (
Const(
"pk(", in,
false)) {
1986 std::optional<Key> key = ParseKey<Key, Ctx>(
"pk", in, ctx);
1987 if (!key)
return {};
1989 script_size +=
IsTapscript(ctx.MsContext()) ? 33 : 34;
1990 }
else if (
Const(
"pkh(", in,
false)) {
1991 std::optional<Key> key = ParseKey<Key, Ctx>(
"pkh", in, ctx);
1992 if (!key)
return {};
1995 }
else if (
Const(
"pk_k(", in,
false)) {
1996 std::optional<Key> key = ParseKey<Key, Ctx>(
"pk_k", in, ctx);
1997 if (!key)
return {};
1999 script_size +=
IsTapscript(ctx.MsContext()) ? 32 : 33;
2000 }
else if (
Const(
"pk_h(", in,
false)) {
2001 std::optional<Key> key = ParseKey<Key, Ctx>(
"pk_h", in, ctx);
2002 if (!key)
return {};
2005 }
else if (
Const(
"sha256(", in,
false)) {
2006 std::optional<std::vector<unsigned char>> hash =
ParseHexStr(
"sha256", in, 32, ctx);
2007 if (!hash)
return {};
2008 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, std::move(*hash));
2010 }
else if (
Const(
"ripemd160(", in,
false)) {
2011 std::optional<std::vector<unsigned char>> hash =
ParseHexStr(
"ripemd160", in, 20, ctx);
2012 if (!hash)
return {};
2015 }
else if (
Const(
"hash256(", in,
false)) {
2016 std::optional<std::vector<unsigned char>> hash =
ParseHexStr(
"hash256", in, 32, ctx);
2017 if (!hash)
return {};
2018 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, std::move(*hash));
2020 }
else if (
Const(
"hash160(", in,
false)) {
2021 std::optional<std::vector<unsigned char>> hash =
ParseHexStr(
"hash160", in, 20, ctx);
2022 if (!hash)
return {};
2023 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, std::move(*hash));
2025 }
else if (
Const(
"after(", in,
false)) {
2026 auto expr =
Expr(in);
2027 if (!
Func(
"after", expr))
return {};
2028 const auto num{ToIntegral<int64_t>(std::string_view(expr.begin(), expr.end()))};
2029 if (!num.has_value() || *num < 1 || *num >= 0x80000000L)
return {};
2031 script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
2032 }
else if (
Const(
"older(", in,
false)) {
2033 auto expr =
Expr(in);
2034 if (!
Func(
"older", expr))
return {};
2035 const auto num{ToIntegral<int64_t>(std::string_view(expr.begin(), expr.end()))};
2036 if (!num.has_value() || *num < 1 || *num >= 0x80000000L)
return {};
2038 script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
2039 }
else if (
Const(
"multi(", in)) {
2040 if (!parse_multi_exp(in,
false))
return {};
2041 }
else if (
Const(
"multi_a(", in)) {
2042 if (!parse_multi_exp(in,
true))
return {};
2043 }
else if (
Const(
"thresh(", in)) {
2045 if (next_comma < 1)
return {};
2046 const auto k{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
2047 if (!
k.has_value() || *
k < 1)
return {};
2048 in = in.subspan(next_comma + 1);
2050 to_parse.emplace_back(ParseContext::THRESH, 1, *
k);
2051 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2052 script_size += 2 + (*
k > 16) + (*
k > 0x7f) + (*
k > 0x7fff) + (*
k > 0x7fffff);
2053 }
else if (
Const(
"andor(", in)) {
2054 to_parse.emplace_back(ParseContext::ANDOR, -1, -1);
2055 to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -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);
2059 to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2060 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2063 if (
Const(
"and_n(", in)) {
2064 to_parse.emplace_back(ParseContext::AND_N, -1, -1);
2066 }
else if (
Const(
"and_b(", in)) {
2067 to_parse.emplace_back(ParseContext::AND_B, -1, -1);
2069 }
else if (
Const(
"and_v(", in)) {
2070 to_parse.emplace_back(ParseContext::AND_V, -1, -1);
2072 }
else if (
Const(
"or_b(", in)) {
2073 to_parse.emplace_back(ParseContext::OR_B, -1, -1);
2075 }
else if (
Const(
"or_c(", in)) {
2076 to_parse.emplace_back(ParseContext::OR_C, -1, -1);
2078 }
else if (
Const(
"or_d(", in)) {
2079 to_parse.emplace_back(ParseContext::OR_D, -1, -1);
2081 }
else if (
Const(
"or_i(", in)) {
2082 to_parse.emplace_back(ParseContext::OR_I, -1, -1);
2087 to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
2088 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2089 to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2090 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2094 case ParseContext::ALT: {
2098 case ParseContext::SWAP: {
2106 case ParseContext::DUP_IF: {
2110 case ParseContext::NON_ZERO: {
2114 case ParseContext::ZERO_NOTEQUAL: {
2118 case ParseContext::VERIFY: {
2119 script_size += (constructed.back().GetType() <<
"x"_mst);
2123 case ParseContext::WRAP_U: {
2124 constructed.back() =
Node{
internal::NoDupCheck{}, ctx.MsContext(), Fragment::OR_I,
Vector(std::move(constructed.back()),
Node<Key>{internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0})};
2127 case ParseContext::WRAP_T: {
2128 constructed.back() =
Node{
internal::NoDupCheck{}, ctx.MsContext(), Fragment::AND_V,
Vector(std::move(constructed.back()),
Node<Key>{internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1})};
2131 case ParseContext::AND_B: {
2132 BuildBack(ctx.MsContext(), Fragment::AND_B, constructed);
2135 case ParseContext::AND_N: {
2136 auto mid = std::move(constructed.back());
2137 constructed.pop_back();
2138 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})};
2141 case ParseContext::AND_V: {
2142 BuildBack(ctx.MsContext(), Fragment::AND_V, constructed);
2145 case ParseContext::OR_B: {
2146 BuildBack(ctx.MsContext(), Fragment::OR_B, constructed);
2149 case ParseContext::OR_C: {
2150 BuildBack(ctx.MsContext(), Fragment::OR_C, constructed);
2153 case ParseContext::OR_D: {
2154 BuildBack(ctx.MsContext(), Fragment::OR_D, constructed);
2157 case ParseContext::OR_I: {
2158 BuildBack(ctx.MsContext(), Fragment::OR_I, constructed);
2161 case ParseContext::ANDOR: {
2162 auto right = std::move(constructed.back());
2163 constructed.pop_back();
2164 auto mid = std::move(constructed.back());
2165 constructed.pop_back();
2166 constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR,
Vector(std::move(constructed.back()), std::move(mid), std::move(right))};
2169 case ParseContext::THRESH: {
2170 if (in.size() < 1)
return {};
2173 to_parse.emplace_back(ParseContext::THRESH, n+1, k);
2174 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2176 }
else if (in[0] ==
')') {
2177 if (k > n)
return {};
2180 std::vector<Node<Key>> subs;
2181 for (
int i = 0; i < n; ++i) {
2182 subs.push_back(std::move(constructed.back()));
2183 constructed.pop_back();
2185 std::reverse(subs.begin(), subs.end());
2186 constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs), k);
2192 case ParseContext::COMMA: {
2193 if (in.size() < 1 || in[0] !=
',')
return {};
2197 case ParseContext::CLOSE_BRACKET: {
2198 if (in.size() < 1 || in[0] !=
')')
return {};
2206 assert(constructed.size() >= 1);
2208 assert(constructed[0].ScriptSize() == script_size);
2209 if (in.size() > 0)
return {};
2210 Node<Key> tl_node{std::move(constructed.front())};
2211 tl_node.DuplicateKeyCheck(ctx);
2297template <
typename Key,
typename Ctx,
typename I>
2301 std::vector<std::tuple<DecodeContext, int64_t, int64_t>> to_parse;
2302 std::vector<Node<Key>> constructed;
2306 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2308 while (!to_parse.empty()) {
2310 if (!constructed.empty() && !constructed.back().IsValid())
return {};
2313 auto [cur_context, n,
k] = to_parse.back();
2314 to_parse.pop_back();
2316 switch(cur_context) {
2317 case DecodeContext::SINGLE_BKV_EXPR: {
2318 if (in >= last)
return {};
2321 if (in[0].first ==
OP_1) {
2326 if (in[0].first ==
OP_0) {
2332 if (in[0].second.size() == 33 || in[0].second.size() == 32) {
2333 auto key = ctx.FromPKBytes(in[0].second.begin(), in[0].second.end());
2334 if (!key)
return {};
2340 auto key = ctx.FromPKHBytes(in[2].second.begin(), in[2].second.end());
2341 if (!key)
return {};
2347 std::optional<int64_t> num;
2350 if (*num < 1 || *num > 0x7FFFFFFFL)
return {};
2356 if (num < 1 || num > 0x7FFFFFFFL)
return {};
2362 if (in[2].first ==
OP_SHA256 && in[1].second.size() == 32) {
2363 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, in[1].second);
2366 }
else if (in[2].first ==
OP_RIPEMD160 && in[1].second.size() == 20) {
2370 }
else if (in[2].first ==
OP_HASH256 && in[1].second.size() == 32) {
2371 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, in[1].second);
2374 }
else if (in[2].first ==
OP_HASH160 && in[1].second.size() == 20) {
2375 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, in[1].second);
2383 std::vector<Key>
keys;
2385 if (!n || last - in < 3 + *n)
return {};
2386 if (*n < 1 || *n > 20)
return {};
2387 for (
int i = 0; i < *n; ++i) {
2388 if (in[2 + i].second.size() != 33)
return {};
2389 auto key = ctx.FromPKBytes(in[2 + i].second.begin(), in[2 + i].second.end());
2390 if (!key)
return {};
2391 keys.push_back(std::move(*key));
2394 if (!
k || *k < 1 || *k > *n)
return {};
2396 std::reverse(
keys.begin(),
keys.end());
2401 if (last - in >= 4 && in[0].first ==
OP_NUMEQUAL) {
2407 if (last - in < 2 + *
k * 2)
return {};
2408 std::vector<Key>
keys;
2411 for (
int pos = 2;; pos += 2) {
2412 if (last - in < pos + 2)
return {};
2415 if (in[pos + 1].second.size() != 32)
return {};
2416 auto key = ctx.FromPKBytes(in[pos + 1].second.begin(), in[pos + 1].second.end());
2417 if (!key)
return {};
2418 keys.push_back(std::move(*key));
2424 if (
keys.size() < (
size_t)*
k)
return {};
2425 in += 2 +
keys.size() * 2;
2426 std::reverse(
keys.begin(),
keys.end());
2437 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2443 to_parse.emplace_back(DecodeContext::VERIFY, -1, -1);
2444 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2450 to_parse.emplace_back(DecodeContext::ZERO_NOTEQUAL, -1, -1);
2451 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2456 if (*num < 1)
return {};
2458 to_parse.emplace_back(DecodeContext::THRESH_W, 0, *num);
2464 to_parse.emplace_back(DecodeContext::ENDIF, -1, -1);
2465 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2476 to_parse.emplace_back(DecodeContext::AND_B, -1, -1);
2477 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2478 to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2484 to_parse.emplace_back(DecodeContext::OR_B, -1, -1);
2485 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2486 to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2492 case DecodeContext::BKV_EXPR: {
2493 to_parse.emplace_back(DecodeContext::MAYBE_AND_V, -1, -1);
2494 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2497 case DecodeContext::W_EXPR: {
2499 if (in >= last)
return {};
2502 to_parse.emplace_back(DecodeContext::ALT, -1, -1);
2504 to_parse.emplace_back(DecodeContext::SWAP, -1, -1);
2506 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2509 case DecodeContext::MAYBE_AND_V: {
2513 to_parse.emplace_back(DecodeContext::AND_V, -1, -1);
2515 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2519 case DecodeContext::SWAP: {
2520 if (in >= last || in[0].first !=
OP_SWAP || constructed.empty())
return {};
2525 case DecodeContext::ALT: {
2526 if (in >= last || in[0].first !=
OP_TOALTSTACK || constructed.empty())
return {};
2532 if (constructed.empty())
return {};
2536 case DecodeContext::DUP_IF: {
2537 if (constructed.empty())
return {};
2541 case DecodeContext::VERIFY: {
2542 if (constructed.empty())
return {};
2546 case DecodeContext::NON_ZERO: {
2547 if (constructed.empty())
return {};
2551 case DecodeContext::ZERO_NOTEQUAL: {
2552 if (constructed.empty())
return {};
2556 case DecodeContext::AND_V: {
2557 if (constructed.size() < 2)
return {};
2558 BuildBack(ctx.MsContext(), Fragment::AND_V, constructed,
true);
2561 case DecodeContext::AND_B: {
2562 if (constructed.size() < 2)
return {};
2563 BuildBack(ctx.MsContext(), Fragment::AND_B, constructed,
true);
2566 case DecodeContext::OR_B: {
2567 if (constructed.size() < 2)
return {};
2568 BuildBack(ctx.MsContext(), Fragment::OR_B, constructed,
true);
2571 case DecodeContext::OR_C: {
2572 if (constructed.size() < 2)
return {};
2573 BuildBack(ctx.MsContext(), Fragment::OR_C, constructed,
true);
2576 case DecodeContext::OR_D: {
2577 if (constructed.size() < 2)
return {};
2578 BuildBack(ctx.MsContext(), Fragment::OR_D, constructed,
true);
2581 case DecodeContext::ANDOR: {
2582 if (constructed.size() < 3)
return {};
2583 Node left{std::move(constructed.back())};
2584 constructed.pop_back();
2585 Node right{std::move(constructed.back())};
2586 constructed.pop_back();
2587 Node mid{std::move(constructed.back())};
2591 case DecodeContext::THRESH_W: {
2592 if (in >= last)
return {};
2593 if (in[0].first ==
OP_ADD) {
2595 to_parse.emplace_back(DecodeContext::THRESH_W, n+1,
k);
2596 to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2598 to_parse.emplace_back(DecodeContext::THRESH_E, n+1,
k);
2600 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2604 case DecodeContext::THRESH_E: {
2605 if (k < 1 || k > n || constructed.size() <
static_cast<size_t>(n))
return {};
2606 std::vector<Node<Key>> subs;
2607 for (
int i = 0; i < n; ++i) {
2608 Node sub{std::move(constructed.back())};
2609 constructed.pop_back();
2610 subs.push_back(std::move(sub));
2612 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs),
k);
2615 case DecodeContext::ENDIF: {
2616 if (in >= last)
return {};
2621 to_parse.emplace_back(DecodeContext::ENDIF_ELSE, -1, -1);
2622 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2625 else if (in[0].first ==
OP_IF) {
2626 if (last - in >= 2 && in[1].first ==
OP_DUP) {
2628 to_parse.emplace_back(DecodeContext::DUP_IF, -1, -1);
2631 to_parse.emplace_back(DecodeContext::NON_ZERO, -1, -1);
2637 }
else if (in[0].first ==
OP_NOTIF) {
2639 to_parse.emplace_back(DecodeContext::ENDIF_NOTIF, -1, -1);
2646 case DecodeContext::ENDIF_NOTIF: {
2647 if (in >= last)
return {};
2650 to_parse.emplace_back(DecodeContext::OR_D, -1, -1);
2652 to_parse.emplace_back(DecodeContext::OR_C, -1, -1);
2655 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2658 case DecodeContext::ENDIF_ELSE: {
2659 if (in >= last)
return {};
2660 if (in[0].first ==
OP_IF) {
2662 BuildBack(ctx.MsContext(), Fragment::OR_I, constructed,
true);
2663 }
else if (in[0].first ==
OP_NOTIF) {
2665 to_parse.emplace_back(DecodeContext::ANDOR, -1, -1);
2667 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2675 if (constructed.size() != 1)
return {};
2676 Node tl_node{std::move(constructed.front())};
2680 if (!tl_node.IsValidTopLevel())
return {};
2686template <
typename Ctx>
2687inline std::optional<Node<typename Ctx::Key>>
FromString(
const std::string& str,
const Ctx& ctx)
2689 return internal::Parse<typename Ctx::Key>(str, ctx);
2692template <
typename Ctx>
2695 using namespace internal;
2699 if (!decomposed)
return {};
2700 auto it = decomposed->begin();
2701 auto ret = DecodeScript<typename Ctx::Key>(it, decomposed->end(), ctx);
2702 if (!
ret)
return {};
2703 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)
std::vector< uint16_t > keys
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.