5#ifndef BITCOIN_SCRIPT_MINISCRIPT_H
6#define BITCOIN_SCRIPT_MINISCRIPT_H
140 friend consteval Type operator""_mst(
const char* c,
size_t l);
162inline consteval Type operator""_mst(
const char* c,
size_t l)
166 for (
const char *p = c; p < c + l; p++) {
178 *p ==
'f' ? 1 << 10 :
179 *p ==
's' ? 1 << 11 :
180 *p ==
'm' ? 1 << 12 :
181 *p ==
'x' ? 1 << 13 :
182 *p ==
'g' ? 1 << 14 :
183 *p ==
'h' ? 1 << 15 :
184 *p ==
'i' ? 1 << 16 :
185 *p ==
'j' ? 1 << 17 :
186 *p ==
'k' ? 1 << 18 :
187 (
throw std::logic_error(
"Unknown character in _mst literal"), 0)
194using Opcode = std::pair<opcodetype, std::vector<unsigned char>>;
196template<
typename Key>
class Node;
199template <
typename Key, std::invocable<const Node<Key>&> Fn>
202 std::vector<std::reference_wrapper<const Node<Key>>> stack{root};
203 while (!stack.empty()) {
205 std::invoke(fn,
node);
207 for (
const auto& sub :
node.Subs()) {
208 stack.emplace_back(sub);
326 std::vector<std::vector<unsigned char>>
stack;
360 template<
typename A,
typename B>
384 if (!a.
valid)
return b;
385 if (!b.
valid)
return a;
456 constexpr SatInfo(int32_t in_netdiff, int32_t in_exec) noexcept :
467 if (!a.valid)
return b;
468 if (!b.valid)
return a;
470 return {std::max(a.netdiff, b.netdiff), std::max(a.exec, b.exec)};
477 if (!a.valid || !b.valid)
return {};
481 return {a.
netdiff + b.netdiff, std::max(b.exec, b.netdiff + a.exec)};
493 static constexpr SatInfo If() noexcept {
return {1, 1}; }
499 static constexpr SatInfo OP_IFDUP(
bool nonzero)
noexcept {
return {nonzero ? -1 : 0, 0}; }
534template <
typename Key>
544 std::vector<unsigned char>
data;
561 std::vector<std::vector<Node>> queue;
562 queue.push_back(std::move(
subs));
564 auto flattening{std::move(queue.back())};
566 for (
Node& n : flattening) {
567 if (!n.subs.empty()) queue.push_back(std::move(n.subs));
569 }
while (!queue.empty());
576 auto upfn = [](
const Node&
node, std::span<Node> children) {
577 std::vector<Node> new_subs;
578 for (
auto& child : children) {
581 new_subs.push_back(std::move(child));
585 return TreeEval<Node>(upfn);
589 uint32_t
K()
const {
return k; }
590 const std::vector<Key>&
Keys()
const {
return keys; }
591 const std::vector<unsigned char>&
Data()
const {
return data; }
592 const std::vector<Node>&
Subs()
const {
return subs; }
616 :
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()) {}
622 for (
const auto& sub :
subs) {
623 subsize += sub.ScriptSize();
625 Type sub0type =
subs.size() > 0 ?
subs[0].GetType() :
""_mst;
652 template<
typename Result,
typename State,
typename DownFn,
typename UpFn>
662 StackElem(
const Node& node_,
size_t exp_,
State&& state_) :
663 node(node_), expanded(exp_), state(std::move(state_)) {}
666 std::vector<StackElem> stack;
669 std::vector<Result> results;
670 stack.emplace_back(*
this, 0, std::move(root_state));
688 while (stack.size()) {
689 const Node&
node = stack.back().node;
690 if (stack.back().expanded <
node.subs.size()) {
694 size_t child_index = stack.back().expanded++;
695 State child_state = downfn(stack.back().state,
node, child_index);
696 stack.emplace_back(
node.subs[child_index], 0, std::move(child_state));
701 std::optional<Result> result{upfn(std::move(stack.back().state),
node,
702 std::span<Result>{results}.last(
node.subs.size()))};
704 if (!result)
return {};
706 results.erase(results.end() -
node.subs.size(), results.end());
707 results.push_back(std::move(*result));
711 assert(results.size() >= 1);
713 return std::move(results[0]);
718 template<
typename Result,
typename UpFn>
721 struct DummyState {};
722 return TreeEvalMaybe<Result>(DummyState{},
723 [](DummyState,
const Node&, size_t) {
return DummyState{}; },
724 [&upfn](DummyState,
const Node&
node, std::span<Result>
subs) {
731 template<
typename Result,
typename State,
typename DownFn,
typename UpFn>
736 return std::move(*TreeEvalMaybe<Result>(std::move(root_state),
737 std::forward<DownFn>(downfn),
740 return std::optional<Result>(std::move(res));
747 template<
typename Result,
typename UpFn>
750 struct DummyState {};
751 return std::move(*TreeEvalMaybe<Result>(DummyState{},
752 [](DummyState,
const Node&, size_t) {
return DummyState{}; },
753 [&upfn](DummyState,
const Node&
node, std::span<Result>
subs) {
755 return std::optional<Result>(std::move(res));
763 std::vector<std::pair<const Node<Key>&,
const Node<Key>&>> queue;
764 queue.emplace_back(node1, node2);
765 while (!queue.empty()) {
766 const auto& [a, b] = queue.back();
768 if (std::tie(a.fragment, a.k, a.keys, a.data) < std::tie(b.fragment, b.k, b.keys, b.data))
return -1;
769 if (std::tie(b.fragment, b.k, b.keys, b.data) < std::tie(a.fragment, a.k, a.keys, a.data))
return 1;
770 if (a.subs.size() < b.subs.size())
return -1;
771 if (b.subs.size() < a.subs.size())
return 1;
772 size_t n = a.
subs.size();
773 for (
size_t i = 0; i < n; ++i) {
774 queue.emplace_back(a.subs[n - 1 - i], b.subs[n - 1 - i]);
782 using namespace internal;
785 std::vector<Type> sub_types;
787 for (
const auto& sub :
subs) sub_types.push_back(sub.GetType());
798 template<
typename Ctx>
817 switch (
node.fragment) {
831 if (
node.subs[0].GetType() <<
"x"_mst) {
834 return std::move(
subs[0]);
851 for (
const auto& key :
node.keys) {
859 for (
auto it =
node.keys.begin() + 1; it !=
node.keys.end(); ++it) {
866 for (
size_t i = 1; i <
subs.size(); ++i) {
874 return TreeEval<CScript>(
false, downfn, upfn);
877 template<
typename CTx>
878 std::optional<std::string>
ToString(
const CTx& ctx)
const {
883 template<
typename CTx>
884 std::optional<std::string>
ToString(
const CTx& ctx,
bool& has_priv_key)
const {
888 auto downfn = [](bool,
const Node&
node, size_t) {
897 auto toString = [&ctx, &has_priv_key](Key key) -> std::optional<std::string> {
898 bool fragment_has_priv_key{
false};
899 auto key_str{ctx.ToString(key, fragment_has_priv_key)};
900 if (key_str) has_priv_key = has_priv_key || fragment_has_priv_key;
906 auto upfn = [is_tapscript, &toString](
bool wrapped,
const Node&
node, std::span<std::string>
subs) -> std::optional<std::string> {
907 std::string
ret = wrapped ?
":" :
"";
909 switch (
node.fragment) {
915 auto key_str = toString(
node.subs[0].keys[0]);
916 if (!key_str)
return {};
917 return std::move(
ret) +
"pk(" + std::move(*key_str) +
")";
921 auto key_str = toString(
node.subs[0].keys[0]);
922 if (!key_str)
return {};
923 return std::move(
ret) +
"pkh(" + std::move(*key_str) +
")";
925 return "c" + std::move(
subs[0]);
940 switch (
node.fragment) {
942 auto key_str = toString(
node.keys[0]);
943 if (!key_str)
return {};
944 return std::move(
ret) +
"pk_k(" + std::move(*key_str) +
")";
947 auto key_str = toString(
node.keys[0]);
948 if (!key_str)
return {};
949 return std::move(
ret) +
"pk_h(" + std::move(*key_str) +
")";
968 return std::move(
ret) +
"andor(" + std::move(
subs[0]) +
"," + std::move(
subs[1]) +
"," + std::move(
subs[2]) +
")";
972 for (
const auto& key :
node.keys) {
973 auto key_str = toString(key);
974 if (!key_str)
return {};
975 str +=
"," + std::move(*key_str);
977 return std::move(str) +
")";
982 for (
const auto& key :
node.keys) {
983 auto key_str = toString(key);
984 if (!key_str)
return {};
985 str +=
"," + std::move(*key_str);
987 return std::move(str) +
")";
991 for (
auto& sub :
subs) {
992 str +=
"," + std::move(sub);
994 return std::move(str) +
")";
1001 return TreeEvalMaybe<std::string>(
false, downfn, upfn);
1019 const auto count{1 +
subs[0].ops.count +
subs[1].ops.count};
1020 const auto sat{
subs[0].ops.sat +
subs[1].ops.sat};
1021 const auto dsat{
subs[0].ops.dsat +
subs[1].ops.dsat};
1022 return {
count, sat, dsat};
1025 const auto count{1 +
subs[0].ops.count +
subs[1].ops.count};
1027 const auto dsat{
subs[0].ops.dsat +
subs[1].ops.dsat};
1028 return {
count, sat, dsat};
1031 const auto count{3 +
subs[0].ops.count +
subs[1].ops.count};
1032 const auto sat{
subs[0].ops.sat | (
subs[1].ops.sat +
subs[0].ops.dsat)};
1033 const auto dsat{
subs[0].ops.dsat +
subs[1].ops.dsat};
1034 return {
count, sat, dsat};
1037 const auto count{2 +
subs[0].ops.count +
subs[1].ops.count};
1038 const auto sat{
subs[0].ops.sat | (
subs[1].ops.sat +
subs[0].ops.dsat)};
1039 return {
count, sat, {}};
1042 const auto count{3 +
subs[0].ops.count +
subs[1].ops.count};
1043 const auto sat{
subs[0].ops.sat |
subs[1].ops.sat};
1044 const auto dsat{
subs[0].ops.dsat |
subs[1].ops.dsat};
1045 return {
count, sat, dsat};
1048 const auto count{3 +
subs[0].ops.count +
subs[1].ops.count +
subs[2].ops.count};
1050 const auto dsat{
subs[0].ops.dsat +
subs[2].ops.dsat};
1051 return {
count, sat, dsat};
1065 for (
const auto& sub :
subs) {
1066 count += sub.ops.count + 1;
1067 auto next_sats =
Vector(sats[0] + sub.ops.dsat);
1068 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub.ops.dsat) | (sats[j - 1] + sub.ops.sat));
1069 next_sats.push_back(sats[sats.size() - 1] + sub.ops.sat);
1070 sats = std::move(next_sats);
1073 return {
count, sats[
k], sats[0]};
1080 using namespace internal;
1096 const auto& x{subs[0].ss};
1097 const auto& y{subs[1].ss};
1098 const auto& z{subs[2].ss};
1100 (x.Sat() + SatInfo::If() + y.Sat()) | (x.Dsat() + SatInfo::If() + z.Sat()),
1101 x.Dsat() + SatInfo::If() + z.Dsat()
1105 const auto& x{subs[0].ss};
1106 const auto& y{subs[1].ss};
1107 return {x.Sat() + y.Sat(), {}};
1110 const auto& x{subs[0].ss};
1111 const auto& y{subs[1].ss};
1112 return {x.Sat() + y.Sat() + SatInfo::BinaryOp(), x.Dsat() + y.Dsat() + SatInfo::BinaryOp()};
1115 const auto& x{subs[0].ss};
1116 const auto& y{subs[1].ss};
1118 ((x.Sat() + y.Dsat()) | (x.Dsat() + y.Sat())) + SatInfo::BinaryOp(),
1119 x.Dsat() + y.Dsat() + SatInfo::BinaryOp()
1123 const auto& x{subs[0].ss};
1124 const auto& y{subs[1].ss};
1125 return {(x.Sat() + SatInfo::If()) | (x.Dsat() + SatInfo::If() + y.Sat()), {}};
1128 const auto& x{subs[0].ss};
1129 const auto& y{subs[1].ss};
1136 const auto& x{subs[0].ss};
1137 const auto& y{subs[1].ss};
1138 return {SatInfo::If() + (x.Sat() | y.Sat()), SatInfo::If() + (x.Dsat() | y.Dsat())};
1167 auto sats =
Vector(SatInfo::Empty());
1168 for (
size_t i = 0; i < subs.size(); ++i) {
1171 auto add = i ? SatInfo::BinaryOp() : SatInfo::Empty();
1173 auto next_sats =
Vector(sats[0] + subs[i].ss.Dsat() + add);
1175 for (
size_t j = 1; j < sats.size(); ++j) {
1176 next_sats.push_back(((sats[j] + subs[i].ss.Dsat()) | (sats[j - 1] + subs[i].ss.Sat())) + add);
1179 next_sats.push_back(sats[sats.size() - 1] + subs[i].ss.Sat() + add);
1181 sats = std::move(next_sats);
1196 const uint32_t pubkey_size =
IsTapscript(m_script_ctx) ? 1 + 32 : 1 + 33;
1209 const auto sat{(subs[0].ws.sat + subs[1].ws.sat) | (subs[0].ws.dsat + subs[2].ws.sat)};
1210 const auto dsat{subs[0].ws.dsat + subs[2].ws.dsat};
1214 case Fragment::AND_B:
return {subs[0].ws.sat + subs[1].ws.sat, subs[0].ws.dsat + subs[1].ws.dsat};
1216 const auto sat{(subs[0].ws.dsat + subs[1].ws.sat) | (subs[0].ws.sat + subs[1].ws.dsat)};
1217 const auto dsat{subs[0].ws.dsat + subs[1].ws.dsat};
1220 case Fragment::OR_C:
return {subs[0].ws.sat | (subs[0].ws.dsat + subs[1].ws.sat), {}};
1221 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};
1222 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)};
1234 for (
const auto& sub : subs) {
1235 auto next_sats =
Vector(sats[0] + sub.ws.dsat);
1236 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub.ws.dsat) | (sats[j - 1] + sub.ws.sat));
1237 next_sats.push_back(sats[sats.size() - 1] + sub.ws.sat);
1238 sats = std::move(next_sats);
1241 return {sats[
k], sats[0]};
1247 template<
typename Ctx>
1249 using namespace internal;
1253 auto helper = [&ctx](
const Node&
node, std::span<InputResult> subres) -> InputResult {
1254 switch (
node.fragment) {
1256 std::vector<unsigned char> sig;
1258 return {
ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
1261 std::vector<unsigned char> key = ctx.ToPKBytes(
node.keys[0]), sig;
1263 return {
ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
1269 for (
size_t i = 0; i <
node.keys.size(); ++i) {
1272 std::vector<unsigned char> sig;
1275 auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1279 std::vector<InputStack> next_sats;
1280 next_sats.push_back(sats[0] +
ZERO);
1281 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] +
ZERO) | (std::move(sats[j - 1]) + sat));
1282 next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1284 sats = std::move(next_sats);
1288 auto& nsat{sats[0]};
1291 return {std::move(nsat), std::move(sats[
node.k])};
1298 for (
size_t i = 0; i <
node.keys.size(); ++i) {
1299 std::vector<unsigned char> sig;
1302 auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1306 std::vector<InputStack> next_sats;
1307 next_sats.push_back(sats[0]);
1308 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
1309 next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1311 sats = std::move(next_sats);
1314 InputStack nsat =
ZERO;
1315 for (
size_t i = 0; i <
node.k; ++i) nsat = std::move(nsat) +
ZERO;
1317 return {std::move(nsat), std::move(sats[
node.k])};
1324 for (
size_t i = 0; i < subres.size(); ++i) {
1326 auto& res = subres[subres.size() - i - 1];
1330 std::vector<InputStack> next_sats;
1331 next_sats.push_back(sats[0] + res.nsat);
1332 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + res.nsat) | (std::move(sats[j - 1]) + res.sat));
1333 next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
1335 sats = std::move(next_sats);
1339 InputStack nsat = INVALID;
1340 for (
size_t i = 0; i < sats.size(); ++i) {
1347 if (i != 0 && i !=
node.k) sats[i].SetMalleable().SetNonCanon();
1349 if (i !=
node.k) nsat = std::move(nsat) | std::move(sats[i]);
1352 return {std::move(nsat), std::move(sats[
node.k])};
1355 return {INVALID, ctx.CheckOlder(
node.k) ?
EMPTY : INVALID};
1358 return {INVALID, ctx.CheckAfter(
node.k) ?
EMPTY : INVALID};
1361 std::vector<unsigned char> preimage;
1363 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1366 std::vector<unsigned char> preimage;
1368 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1371 std::vector<unsigned char> preimage;
1373 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1376 std::vector<unsigned char> preimage;
1378 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
1381 auto& x = subres[0], &y = subres[1];
1388 return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
1391 auto& x = subres[0], &y = subres[1];
1397 return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
1400 auto& x = subres[0], &z = subres[1];
1402 return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
1405 auto& x = subres[0], &z = subres[1];
1406 return {INVALID, std::move(x.sat) | (z.sat + x.nsat)};
1409 auto& x = subres[0], &z = subres[1];
1410 return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
1413 auto& x = subres[0], &z = subres[1];
1414 return {(x.nsat + ONE) | (z.nsat +
ZERO), (x.sat + ONE) | (z.sat +
ZERO)};
1417 auto& x = subres[0], &y = subres[1], &z = subres[2];
1418 return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
1424 return std::move(subres[0]);
1426 auto &x = subres[0];
1427 return {
ZERO, x.sat + ONE};
1430 auto &x = subres[0];
1436 return {InputStack(
ZERO).SetMalleable(x.nsat.available !=
Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
1439 auto &x = subres[0];
1440 return {INVALID, std::move(x.sat)};
1446 return {INVALID, INVALID};
1449 auto tester = [&helper](
const Node&
node, std::span<InputResult> subres) -> InputResult {
1450 auto ret = helper(
node, subres);
1492 return TreeEval<InputResult>(tester);
1507 Comp(
const Ctx& ctx) : ctx_ptr(&ctx) {}
1508 bool operator()(
const Key& a,
const Key& b)
const {
return ctx_ptr->KeyCompare(a, b); }
1514 using keyset = std::set<Key, Comp>;
1515 using state = std::optional<keyset>;
1517 auto upfn = [&ctx](
const Node&
node, std::span<state> subs) -> state {
1519 if (
node.has_duplicate_keys.has_value() && *
node.has_duplicate_keys)
return {};
1522 for (
auto& sub : subs) {
1523 if (!sub.has_value()) {
1524 node.has_duplicate_keys =
true;
1531 size_t keys_count =
node.keys.size();
1532 keyset key_set{
node.keys.begin(),
node.keys.end(), Comp(ctx)};
1533 if (key_set.size() != keys_count) {
1535 node.has_duplicate_keys =
true;
1540 for (
auto& sub : subs) {
1541 keys_count += sub->size();
1544 if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1545 key_set.merge(*sub);
1546 if (key_set.size() != keys_count) {
1547 node.has_duplicate_keys =
true;
1552 node.has_duplicate_keys =
false;
1556 TreeEval<state>(upfn);
1564 if (!ops.sat.Valid())
return {};
1565 return ops.count + ops.sat.Value();
1580 return !((GetType() &
"BKW"_mst) ==
""_mst);
1585 if (!ss.Sat().Valid())
return {};
1586 return ss.Sat().NetDiff() +
static_cast<int32_t
>(IsBKW());
1591 if (!ss.Sat().Valid())
return {};
1592 return ss.Sat().Exec() +
static_cast<int32_t
>(IsBKW());
1600 if (
const auto exec_ss = GetExecStackSize())
return exec_ss <=
MAX_STACK_SIZE;
1613 if (!ws.sat.Valid())
return {};
1614 return ws.sat.Value();
1625 return TreeEval<const Node*>([](
const Node&
node, std::span<const Node*> subs) ->
const Node* {
1626 for (
auto& sub: subs)
if (sub)
return sub;
1627 if (!
node.IsSaneSubexpression())
return &
node;
1634 template<
typename F>
1638 return TreeEval<int>([&fn](
const Node&
node, std::span<int> subs) ->
bool {
1639 switch (
node.fragment) {
1640 case Fragment::JUST_0:
1642 case Fragment::JUST_1:
1644 case Fragment::PK_K:
1645 case Fragment::PK_H:
1646 case Fragment::MULTI:
1647 case Fragment::MULTI_A:
1648 case Fragment::AFTER:
1649 case Fragment::OLDER:
1650 case Fragment::HASH256:
1651 case Fragment::HASH160:
1652 case Fragment::SHA256:
1653 case Fragment::RIPEMD160:
1654 return bool{fn(node)};
1656 return (subs[0] && subs[1]) || subs[2];
1659 return subs[0] && subs[1];
1664 return subs[0] || subs[1];
1666 return static_cast<uint32_t
>(
std::count(subs.begin(), subs.end(),
true)) >=
node.k;
1668 assert(subs.size() >= 1);
1677 if (GetType() ==
""_mst)
return false;
1700 bool IsSaneSubexpression()
const {
return ValidSatisfactions() && IsNonMalleable() && CheckTimeLocksMix() && CheckDuplicateKey(); }
1703 bool IsSane()
const {
return IsValidTopLevel() && IsSaneSubexpression() && NeedsSignature(); }
1709 template<
typename Ctx>
1710 Availability Satisfy(
const Ctx& ctx, std::vector<std::vector<unsigned char>>& stack,
bool nonmalleable =
true)
const {
1711 auto ret = ProduceInput(ctx);
1712 if (nonmalleable && (
ret.sat.malleable || !
ret.sat.has_sig))
return Availability::NO;
1713 stack = std::move(
ret.sat.stack);
1714 return ret.sat.available;
1722 : 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()) {}
1724 : fragment(nt),
k(val),
data(
std::move(arg)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1726 : 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()) {}
1728 : fragment(nt),
k(val),
keys(
std::move(key)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1730 : fragment(nt),
k(val), subs(
std::move(sub)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1732 : fragment(nt),
k(val), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1735 template <
typename Ctx>
Node(
const Ctx& ctx,
enum Fragment nt, std::vector<Node> sub, std::vector<unsigned char> arg, uint32_t val = 0)
1736 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(sub),
std::move(arg), val) { DuplicateKeyCheck(ctx); }
1737 template <
typename Ctx>
Node(
const Ctx& ctx,
enum Fragment nt, std::vector<unsigned char> arg, uint32_t val = 0)
1738 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(arg), val) { DuplicateKeyCheck(ctx);}
1739 template <
typename Ctx>
Node(
const Ctx& ctx,
enum Fragment nt, std::vector<Node> sub, std::vector<Key> key, uint32_t val = 0)
1740 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(sub),
std::move(key), val) { DuplicateKeyCheck(ctx); }
1741 template <
typename Ctx>
Node(
const Ctx& ctx,
enum Fragment nt, std::vector<Key> key, uint32_t val = 0)
1742 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(key), val) { DuplicateKeyCheck(ctx); }
1743 template <
typename Ctx>
Node(
const Ctx& ctx,
enum Fragment nt, std::vector<Node> sub, uint32_t val = 0)
1744 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(sub), val) { DuplicateKeyCheck(ctx); }
1745 template <
typename Ctx>
Node(
const Ctx& ctx,
enum Fragment nt, uint32_t val = 0)
1746 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt, val) { DuplicateKeyCheck(ctx); }
1816template<
typename Key,
typename Ctx>
1817std::optional<Key>
ParseKey(
const std::string& func, std::span<const char>& in,
const Ctx& ctx)
1821 return ctx.FromString(expr);
1825template<
typename Ctx>
1826std::optional<std::vector<unsigned char>>
ParseHexStr(
const std::string& func, std::span<const char>& in,
const size_t expected_size,
1831 std::string val = std::string(expr.begin(), expr.end());
1832 if (!
IsHex(val))
return {};
1834 if (hash.size() != expected_size)
return {};
1839template<
typename Key>
1842 Node<Key> child{std::move(constructed.back())};
1843 constructed.pop_back();
1856template <
typename Key,
typename Ctx>
1857inline std::optional<Node<Key>>
Parse(std::span<const char> in,
const Ctx& ctx)
1871 size_t script_size{1};
1875 std::vector<std::tuple<ParseContext, int64_t, int64_t>> to_parse;
1876 std::vector<Node<Key>> constructed;
1878 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
1881 const auto parse_multi_exp = [&](std::span<const char>& in,
const bool is_multi_a) ->
bool {
1883 const auto required_ctx{is_multi_a ? MiniscriptContext::TAPSCRIPT : MiniscriptContext::P2WSH};
1884 if (ctx.MsContext() != required_ctx)
return false;
1887 if (next_comma < 1)
return false;
1888 const auto k_to_integral{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
1889 if (!k_to_integral.has_value())
return false;
1890 const int64_t
k{k_to_integral.value()};
1891 in = in.subspan(next_comma + 1);
1893 std::vector<Key>
keys;
1894 while (next_comma != -1) {
1896 int key_length = (next_comma == -1) ?
FindNextChar(in,
')') : next_comma;
1897 if (key_length < 1)
return false;
1898 std::span<const char> sp{in.begin(), in.begin() + key_length};
1899 auto key = ctx.FromString(sp);
1900 if (!key)
return false;
1901 keys.push_back(std::move(*key));
1902 in = in.subspan(key_length + 1);
1904 if (
keys.size() < 1 ||
keys.size() > max_keys)
return false;
1905 if (k < 1 || k > (int64_t)
keys.size())
return false;
1911 script_size += 2 + (
keys.size() > 16) + (
k > 16) + 34 *
keys.size();
1917 while (!to_parse.empty()) {
1918 if (script_size > max_size)
return {};
1921 auto [cur_context, n,
k] = to_parse.back();
1922 to_parse.pop_back();
1924 switch (cur_context) {
1925 case ParseContext::WRAPPED_EXPR: {
1926 std::optional<size_t> colon_index{};
1927 for (
size_t i = 1; i < in.size(); ++i) {
1932 if (in[i] <
'a' || in[i] >
'z')
break;
1935 bool last_was_v{
false};
1936 for (
size_t j = 0; colon_index && j < *colon_index; ++j) {
1937 if (script_size > max_size)
return {};
1940 to_parse.emplace_back(ParseContext::ALT, -1, -1);
1941 }
else if (in[j] ==
's') {
1943 to_parse.emplace_back(ParseContext::SWAP, -1, -1);
1944 }
else if (in[j] ==
'c') {
1947 }
else if (in[j] ==
'd') {
1949 to_parse.emplace_back(ParseContext::DUP_IF, -1, -1);
1950 }
else if (in[j] ==
'j') {
1952 to_parse.emplace_back(ParseContext::NON_ZERO, -1, -1);
1953 }
else if (in[j] ==
'n') {
1955 to_parse.emplace_back(ParseContext::ZERO_NOTEQUAL, -1, -1);
1956 }
else if (in[j] ==
'v') {
1959 if (last_was_v)
return {};
1960 to_parse.emplace_back(ParseContext::VERIFY, -1, -1);
1961 }
else if (in[j] ==
'u') {
1963 to_parse.emplace_back(ParseContext::WRAP_U, -1, -1);
1964 }
else if (in[j] ==
't') {
1966 to_parse.emplace_back(ParseContext::WRAP_T, -1, -1);
1967 }
else if (in[j] ==
'l') {
1971 to_parse.emplace_back(ParseContext::OR_I, -1, -1);
1975 last_was_v = (in[j] ==
'v');
1977 to_parse.emplace_back(ParseContext::EXPR, -1, -1);
1978 if (colon_index) in = in.subspan(*colon_index + 1);
1981 case ParseContext::EXPR: {
1982 if (
Const(
"0", in)) {
1984 }
else if (
Const(
"1", in)) {
1986 }
else if (
Const(
"pk(", in,
false)) {
1987 std::optional<Key> key = ParseKey<Key, Ctx>(
"pk", in, ctx);
1988 if (!key)
return {};
1990 script_size +=
IsTapscript(ctx.MsContext()) ? 33 : 34;
1991 }
else if (
Const(
"pkh(", in,
false)) {
1992 std::optional<Key> key = ParseKey<Key, Ctx>(
"pkh", in, ctx);
1993 if (!key)
return {};
1996 }
else if (
Const(
"pk_k(", in,
false)) {
1997 std::optional<Key> key = ParseKey<Key, Ctx>(
"pk_k", in, ctx);
1998 if (!key)
return {};
2000 script_size +=
IsTapscript(ctx.MsContext()) ? 32 : 33;
2001 }
else if (
Const(
"pk_h(", in,
false)) {
2002 std::optional<Key> key = ParseKey<Key, Ctx>(
"pk_h", in, ctx);
2003 if (!key)
return {};
2006 }
else if (
Const(
"sha256(", in,
false)) {
2007 std::optional<std::vector<unsigned char>> hash =
ParseHexStr(
"sha256", in, 32, ctx);
2008 if (!hash)
return {};
2009 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, std::move(*hash));
2011 }
else if (
Const(
"ripemd160(", in,
false)) {
2012 std::optional<std::vector<unsigned char>> hash =
ParseHexStr(
"ripemd160", in, 20, ctx);
2013 if (!hash)
return {};
2016 }
else if (
Const(
"hash256(", in,
false)) {
2017 std::optional<std::vector<unsigned char>> hash =
ParseHexStr(
"hash256", in, 32, ctx);
2018 if (!hash)
return {};
2019 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, std::move(*hash));
2021 }
else if (
Const(
"hash160(", in,
false)) {
2022 std::optional<std::vector<unsigned char>> hash =
ParseHexStr(
"hash160", in, 20, ctx);
2023 if (!hash)
return {};
2024 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, std::move(*hash));
2026 }
else if (
Const(
"after(", in,
false)) {
2027 auto expr =
Expr(in);
2028 if (!
Func(
"after", expr))
return {};
2029 const auto num{ToIntegral<int64_t>(std::string_view(expr.begin(), expr.end()))};
2030 if (!num.has_value() || *num < 1 || *num >= 0x80000000L)
return {};
2032 script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
2033 }
else if (
Const(
"older(", in,
false)) {
2034 auto expr =
Expr(in);
2035 if (!
Func(
"older", expr))
return {};
2036 const auto num{ToIntegral<int64_t>(std::string_view(expr.begin(), expr.end()))};
2037 if (!num.has_value() || *num < 1 || *num >= 0x80000000L)
return {};
2039 script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
2040 }
else if (
Const(
"multi(", in)) {
2041 if (!parse_multi_exp(in,
false))
return {};
2042 }
else if (
Const(
"multi_a(", in)) {
2043 if (!parse_multi_exp(in,
true))
return {};
2044 }
else if (
Const(
"thresh(", in)) {
2046 if (next_comma < 1)
return {};
2047 const auto k{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
2048 if (!
k.has_value() || *
k < 1)
return {};
2049 in = in.subspan(next_comma + 1);
2051 to_parse.emplace_back(ParseContext::THRESH, 1, *
k);
2052 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2053 script_size += 2 + (*
k > 16) + (*
k > 0x7f) + (*
k > 0x7fff) + (*
k > 0x7fffff);
2054 }
else if (
Const(
"andor(", in)) {
2055 to_parse.emplace_back(ParseContext::ANDOR, -1, -1);
2056 to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
2057 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2058 to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2059 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2060 to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2061 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2064 if (
Const(
"and_n(", in)) {
2065 to_parse.emplace_back(ParseContext::AND_N, -1, -1);
2067 }
else if (
Const(
"and_b(", in)) {
2068 to_parse.emplace_back(ParseContext::AND_B, -1, -1);
2070 }
else if (
Const(
"and_v(", in)) {
2071 to_parse.emplace_back(ParseContext::AND_V, -1, -1);
2073 }
else if (
Const(
"or_b(", in)) {
2074 to_parse.emplace_back(ParseContext::OR_B, -1, -1);
2076 }
else if (
Const(
"or_c(", in)) {
2077 to_parse.emplace_back(ParseContext::OR_C, -1, -1);
2079 }
else if (
Const(
"or_d(", in)) {
2080 to_parse.emplace_back(ParseContext::OR_D, -1, -1);
2082 }
else if (
Const(
"or_i(", in)) {
2083 to_parse.emplace_back(ParseContext::OR_I, -1, -1);
2088 to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
2089 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2090 to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2091 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2095 case ParseContext::ALT: {
2099 case ParseContext::SWAP: {
2107 case ParseContext::DUP_IF: {
2111 case ParseContext::NON_ZERO: {
2115 case ParseContext::ZERO_NOTEQUAL: {
2119 case ParseContext::VERIFY: {
2120 script_size += (constructed.back().GetType() <<
"x"_mst);
2124 case ParseContext::WRAP_U: {
2125 constructed.back() =
Node{
internal::NoDupCheck{}, ctx.MsContext(), Fragment::OR_I,
Vector(std::move(constructed.back()),
Node<Key>{internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0})};
2128 case ParseContext::WRAP_T: {
2129 constructed.back() =
Node{
internal::NoDupCheck{}, ctx.MsContext(), Fragment::AND_V,
Vector(std::move(constructed.back()),
Node<Key>{internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1})};
2132 case ParseContext::AND_B: {
2133 BuildBack(ctx.MsContext(), Fragment::AND_B, constructed);
2136 case ParseContext::AND_N: {
2137 auto mid = std::move(constructed.back());
2138 constructed.pop_back();
2139 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})};
2142 case ParseContext::AND_V: {
2143 BuildBack(ctx.MsContext(), Fragment::AND_V, constructed);
2146 case ParseContext::OR_B: {
2147 BuildBack(ctx.MsContext(), Fragment::OR_B, constructed);
2150 case ParseContext::OR_C: {
2151 BuildBack(ctx.MsContext(), Fragment::OR_C, constructed);
2154 case ParseContext::OR_D: {
2155 BuildBack(ctx.MsContext(), Fragment::OR_D, constructed);
2158 case ParseContext::OR_I: {
2159 BuildBack(ctx.MsContext(), Fragment::OR_I, constructed);
2162 case ParseContext::ANDOR: {
2163 auto right = std::move(constructed.back());
2164 constructed.pop_back();
2165 auto mid = std::move(constructed.back());
2166 constructed.pop_back();
2167 constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR,
Vector(std::move(constructed.back()), std::move(mid), std::move(right))};
2170 case ParseContext::THRESH: {
2171 if (in.size() < 1)
return {};
2174 to_parse.emplace_back(ParseContext::THRESH, n+1, k);
2175 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2177 }
else if (in[0] ==
')') {
2178 if (k > n)
return {};
2181 std::vector<Node<Key>> subs;
2182 for (
int i = 0; i < n; ++i) {
2183 subs.push_back(std::move(constructed.back()));
2184 constructed.pop_back();
2186 std::reverse(subs.begin(), subs.end());
2187 constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs), k);
2193 case ParseContext::COMMA: {
2194 if (in.size() < 1 || in[0] !=
',')
return {};
2198 case ParseContext::CLOSE_BRACKET: {
2199 if (in.size() < 1 || in[0] !=
')')
return {};
2207 assert(constructed.size() >= 1);
2209 assert(constructed[0].ScriptSize() == script_size);
2210 if (in.size() > 0)
return {};
2211 Node<Key> tl_node{std::move(constructed.front())};
2212 tl_node.DuplicateKeyCheck(ctx);
2298template <
typename Key,
typename Ctx,
typename I>
2302 std::vector<std::tuple<DecodeContext, int64_t, int64_t>> to_parse;
2303 std::vector<Node<Key>> constructed;
2307 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2309 while (!to_parse.empty()) {
2311 if (!constructed.empty() && !constructed.back().IsValid())
return {};
2314 auto [cur_context, n,
k] = to_parse.back();
2315 to_parse.pop_back();
2317 switch(cur_context) {
2318 case DecodeContext::SINGLE_BKV_EXPR: {
2319 if (in >= last)
return {};
2322 if (in[0].first ==
OP_1) {
2327 if (in[0].first ==
OP_0) {
2333 if (in[0].second.size() == 33 || in[0].second.size() == 32) {
2334 auto key = ctx.FromPKBytes(in[0].second.begin(), in[0].second.end());
2335 if (!key)
return {};
2341 auto key = ctx.FromPKHBytes(in[2].second.begin(), in[2].second.end());
2342 if (!key)
return {};
2348 std::optional<int64_t> num;
2351 if (*num < 1 || *num > 0x7FFFFFFFL)
return {};
2357 if (num < 1 || num > 0x7FFFFFFFL)
return {};
2363 if (in[2].first ==
OP_SHA256 && in[1].second.size() == 32) {
2364 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, in[1].second);
2367 }
else if (in[2].first ==
OP_RIPEMD160 && in[1].second.size() == 20) {
2371 }
else if (in[2].first ==
OP_HASH256 && in[1].second.size() == 32) {
2372 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, in[1].second);
2375 }
else if (in[2].first ==
OP_HASH160 && in[1].second.size() == 20) {
2376 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, in[1].second);
2384 std::vector<Key>
keys;
2386 if (!n || last - in < 3 + *n)
return {};
2387 if (*n < 1 || *n > 20)
return {};
2388 for (
int i = 0; i < *n; ++i) {
2389 if (in[2 + i].second.size() != 33)
return {};
2390 auto key = ctx.FromPKBytes(in[2 + i].second.begin(), in[2 + i].second.end());
2391 if (!key)
return {};
2392 keys.push_back(std::move(*key));
2395 if (!
k || *k < 1 || *k > *n)
return {};
2397 std::reverse(
keys.begin(),
keys.end());
2402 if (last - in >= 4 && in[0].first ==
OP_NUMEQUAL) {
2408 if (last - in < 2 + *
k * 2)
return {};
2409 std::vector<Key>
keys;
2412 for (
int pos = 2;; pos += 2) {
2413 if (last - in < pos + 2)
return {};
2416 if (in[pos + 1].second.size() != 32)
return {};
2417 auto key = ctx.FromPKBytes(in[pos + 1].second.begin(), in[pos + 1].second.end());
2418 if (!key)
return {};
2419 keys.push_back(std::move(*key));
2425 if (
keys.size() < (
size_t)*
k)
return {};
2426 in += 2 +
keys.size() * 2;
2427 std::reverse(
keys.begin(),
keys.end());
2438 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2444 to_parse.emplace_back(DecodeContext::VERIFY, -1, -1);
2445 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2451 to_parse.emplace_back(DecodeContext::ZERO_NOTEQUAL, -1, -1);
2452 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2457 if (*num < 1)
return {};
2459 to_parse.emplace_back(DecodeContext::THRESH_W, 0, *num);
2465 to_parse.emplace_back(DecodeContext::ENDIF, -1, -1);
2466 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2477 to_parse.emplace_back(DecodeContext::AND_B, -1, -1);
2478 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2479 to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2485 to_parse.emplace_back(DecodeContext::OR_B, -1, -1);
2486 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2487 to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2493 case DecodeContext::BKV_EXPR: {
2494 to_parse.emplace_back(DecodeContext::MAYBE_AND_V, -1, -1);
2495 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2498 case DecodeContext::W_EXPR: {
2500 if (in >= last)
return {};
2503 to_parse.emplace_back(DecodeContext::ALT, -1, -1);
2505 to_parse.emplace_back(DecodeContext::SWAP, -1, -1);
2507 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2510 case DecodeContext::MAYBE_AND_V: {
2514 to_parse.emplace_back(DecodeContext::AND_V, -1, -1);
2516 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2520 case DecodeContext::SWAP: {
2521 if (in >= last || in[0].first !=
OP_SWAP || constructed.empty())
return {};
2526 case DecodeContext::ALT: {
2527 if (in >= last || in[0].first !=
OP_TOALTSTACK || constructed.empty())
return {};
2533 if (constructed.empty())
return {};
2537 case DecodeContext::DUP_IF: {
2538 if (constructed.empty())
return {};
2542 case DecodeContext::VERIFY: {
2543 if (constructed.empty())
return {};
2547 case DecodeContext::NON_ZERO: {
2548 if (constructed.empty())
return {};
2552 case DecodeContext::ZERO_NOTEQUAL: {
2553 if (constructed.empty())
return {};
2557 case DecodeContext::AND_V: {
2558 if (constructed.size() < 2)
return {};
2559 BuildBack(ctx.MsContext(), Fragment::AND_V, constructed,
true);
2562 case DecodeContext::AND_B: {
2563 if (constructed.size() < 2)
return {};
2564 BuildBack(ctx.MsContext(), Fragment::AND_B, constructed,
true);
2567 case DecodeContext::OR_B: {
2568 if (constructed.size() < 2)
return {};
2569 BuildBack(ctx.MsContext(), Fragment::OR_B, constructed,
true);
2572 case DecodeContext::OR_C: {
2573 if (constructed.size() < 2)
return {};
2574 BuildBack(ctx.MsContext(), Fragment::OR_C, constructed,
true);
2577 case DecodeContext::OR_D: {
2578 if (constructed.size() < 2)
return {};
2579 BuildBack(ctx.MsContext(), Fragment::OR_D, constructed,
true);
2582 case DecodeContext::ANDOR: {
2583 if (constructed.size() < 3)
return {};
2584 Node left{std::move(constructed.back())};
2585 constructed.pop_back();
2586 Node right{std::move(constructed.back())};
2587 constructed.pop_back();
2588 Node mid{std::move(constructed.back())};
2592 case DecodeContext::THRESH_W: {
2593 if (in >= last)
return {};
2594 if (in[0].first ==
OP_ADD) {
2596 to_parse.emplace_back(DecodeContext::THRESH_W, n+1,
k);
2597 to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2599 to_parse.emplace_back(DecodeContext::THRESH_E, n+1,
k);
2601 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2605 case DecodeContext::THRESH_E: {
2606 if (k < 1 || k > n || constructed.size() <
static_cast<size_t>(n))
return {};
2607 std::vector<Node<Key>> subs;
2608 for (
int i = 0; i < n; ++i) {
2609 Node sub{std::move(constructed.back())};
2610 constructed.pop_back();
2611 subs.push_back(std::move(sub));
2613 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs),
k);
2616 case DecodeContext::ENDIF: {
2617 if (in >= last)
return {};
2622 to_parse.emplace_back(DecodeContext::ENDIF_ELSE, -1, -1);
2623 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2626 else if (in[0].first ==
OP_IF) {
2627 if (last - in >= 2 && in[1].first ==
OP_DUP) {
2629 to_parse.emplace_back(DecodeContext::DUP_IF, -1, -1);
2632 to_parse.emplace_back(DecodeContext::NON_ZERO, -1, -1);
2638 }
else if (in[0].first ==
OP_NOTIF) {
2640 to_parse.emplace_back(DecodeContext::ENDIF_NOTIF, -1, -1);
2647 case DecodeContext::ENDIF_NOTIF: {
2648 if (in >= last)
return {};
2651 to_parse.emplace_back(DecodeContext::OR_D, -1, -1);
2653 to_parse.emplace_back(DecodeContext::OR_C, -1, -1);
2656 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2659 case DecodeContext::ENDIF_ELSE: {
2660 if (in >= last)
return {};
2661 if (in[0].first ==
OP_IF) {
2663 BuildBack(ctx.MsContext(), Fragment::OR_I, constructed,
true);
2664 }
else if (in[0].first ==
OP_NOTIF) {
2666 to_parse.emplace_back(DecodeContext::ANDOR, -1, -1);
2668 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2676 if (constructed.size() != 1)
return {};
2677 Node tl_node{std::move(constructed.front())};
2681 if (!tl_node.IsValidTopLevel())
return {};
2687template <
typename Ctx>
2688inline std::optional<Node<typename Ctx::Key>>
FromString(
const std::string& str,
const Ctx& ctx)
2690 return internal::Parse<typename Ctx::Key>(str, ctx);
2693template <
typename Ctx>
2696 using namespace internal;
2700 if (!decomposed)
return {};
2701 auto it = decomposed->begin();
2702 auto ret = DecodeScript<typename Ctx::Key>(it, decomposed->end(), ctx);
2703 if (!
ret)
return {};
2704 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.