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);
1824inline std::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;
1908 script_size += 2 + (
keys.size() > 16) + (
k > 16) + 34 *
keys.size();
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);
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);
2010 if (!hash)
return {};
2013 }
else if (
Const(
"hash256(", in,
false)) {
2014 std::optional<std::vector<unsigned char>> hash =
ParseHexStr(
"hash256", in, 32);
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);
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());
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());
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 PrecomputedData data
Precomputed COutPoint and CCoins values.
constexpr 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...
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
const auto ONE
A stack consisting of a single 0x01 element (interpreted as 1 by the script interpreted in numeric co...
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
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'.
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.
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).
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.
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...
std::optional< std::vector< unsigned char > > ParseHexStr(const std::string &func, std::span< const char > &in, const size_t expected_size)
Parse a hex string fully contained within a fragment with the name given by 'func'.
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.
constexpr unsigned int MAX_STANDARD_P2WSH_STACK_ITEMS
The maximum number of witness stack items in a standard P2WSH script.
constexpr int32_t MAX_STANDARD_TX_WEIGHT
The maximum weight for transactions we're willing to relay/mine.
constexpr unsigned int MAX_STANDARD_P2WSH_SCRIPT_SIZE
The maximum size in bytes of a standard witnessScript.
constexpr unsigned int MAX_PUBKEYS_PER_MULTI_A
The limit of keys in OP_CHECKSIGADD-based scripts.
constexpr int MAX_PUBKEYS_PER_MULTISIG
constexpr int MAX_STACK_SIZE
CScript BuildScript(Ts &&... inputs)
Build a script by concatenating other scripts, or any argument accepted by CScript::operator<<.
constexpr int MAX_OPS_PER_SCRIPT
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
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.