5#ifndef BITCOIN_SCRIPT_MINISCRIPT_H
6#define BITCOIN_SCRIPT_MINISCRIPT_H
137 friend consteval Type operator""_mst(
const char* c,
size_t l);
159inline consteval Type operator""_mst(
const char* c,
size_t l)
163 for (
const char *p = c; p < c + l; p++) {
175 *p ==
'f' ? 1 << 10 :
176 *p ==
's' ? 1 << 11 :
177 *p ==
'm' ? 1 << 12 :
178 *p ==
'x' ? 1 << 13 :
179 *p ==
'g' ? 1 << 14 :
180 *p ==
'h' ? 1 << 15 :
181 *p ==
'i' ? 1 << 16 :
182 *p ==
'j' ? 1 << 17 :
183 *p ==
'k' ? 1 << 18 :
184 (
throw std::logic_error(
"Unknown character in _mst literal"), 0)
191using Opcode = std::pair<opcodetype, std::vector<unsigned char>>;
193template<
typename Key>
class Node;
196template <
typename Key, std::invocable<const Node<Key>&> Fn>
199 std::vector<std::reference_wrapper<const Node<Key>>> stack{root};
200 while (!stack.empty()) {
202 std::invoke(fn,
node);
204 for (
const auto& sub :
node.Subs()) {
205 stack.emplace_back(sub);
323 std::vector<std::vector<unsigned char>>
stack;
357 template<
typename A,
typename B>
381 if (!a.
valid)
return b;
382 if (!b.
valid)
return a;
453 constexpr SatInfo(int32_t in_netdiff, int32_t in_exec) noexcept :
464 if (!a.valid)
return b;
465 if (!b.valid)
return a;
467 return {std::max(a.netdiff, b.netdiff), std::max(a.exec, b.exec)};
474 if (!a.valid || !b.valid)
return {};
478 return {a.
netdiff + b.netdiff, std::max(b.exec, b.netdiff + a.exec)};
490 static constexpr SatInfo If() noexcept {
return {1, 1}; }
496 static constexpr SatInfo OP_IFDUP(
bool nonzero)
noexcept {
return {nonzero ? -1 : 0, 0}; }
531template <
typename Key>
541 std::vector<unsigned char>
data;
555 std::vector<std::vector<Node>> queue;
556 queue.push_back(std::move(
subs));
558 auto flattening{std::move(queue.back())};
560 for (
Node& n : flattening) {
561 if (!n.subs.empty()) queue.push_back(std::move(n.subs));
563 }
while (!queue.empty());
570 auto upfn = [](
const Node&
node, std::span<Node> children) {
571 std::vector<Node> new_subs;
572 for (
auto& child : children) {
575 new_subs.push_back(std::move(child));
579 return TreeEval<Node>(upfn);
583 uint32_t
K()
const {
return k; }
584 const std::vector<Key>&
Keys()
const {
return keys; }
585 const std::vector<unsigned char>&
Data()
const {
return data; }
586 const std::vector<Node>&
Subs()
const {
return subs; }
610 :
fragment(nt),
k(val),
keys(key),
data(
std::move(arg)),
subs(
std::move(sub)),
m_script_ctx{script_ctx},
ops(
CalcOps()),
ss(
CalcStackSize()),
ws(
CalcWitnessSize()),
typ(
CalcType()),
scriptlen(
CalcScriptLen()) {}
616 for (
const auto& sub :
subs) {
617 subsize += sub.ScriptSize();
619 Type sub0type =
subs.size() > 0 ?
subs[0].GetType() :
""_mst;
646 template<
typename Result,
typename State,
typename DownFn,
typename UpFn>
656 StackElem(
const Node& node_,
size_t exp_,
State&& state_) :
657 node(node_), expanded(exp_), state(std::move(state_)) {}
660 std::vector<StackElem> stack;
663 std::vector<Result> results;
664 stack.emplace_back(*
this, 0, std::move(root_state));
682 while (stack.size()) {
683 const Node&
node = stack.back().node;
684 if (stack.back().expanded <
node.subs.size()) {
688 size_t child_index = stack.back().expanded++;
689 State child_state = downfn(stack.back().state,
node, child_index);
690 stack.emplace_back(
node.subs[child_index], 0, std::move(child_state));
695 std::optional<Result> result{upfn(std::move(stack.back().state),
node,
696 std::span<Result>{results}.last(
node.subs.size()))};
698 if (!result)
return {};
700 results.erase(results.end() -
node.subs.size(), results.end());
701 results.push_back(std::move(*result));
705 assert(results.size() >= 1);
707 return std::move(results[0]);
712 template<
typename Result,
typename UpFn>
715 struct DummyState {};
716 return TreeEvalMaybe<Result>(DummyState{},
717 [](DummyState,
const Node&, size_t) {
return DummyState{}; },
718 [&upfn](DummyState,
const Node&
node, std::span<Result>
subs) {
725 template<
typename Result,
typename State,
typename DownFn,
typename UpFn>
730 return std::move(*TreeEvalMaybe<Result>(std::move(root_state),
731 std::forward<DownFn>(downfn),
734 return std::optional<Result>(std::move(res));
741 template<
typename Result,
typename UpFn>
744 struct DummyState {};
745 return std::move(*TreeEvalMaybe<Result>(DummyState{},
746 [](DummyState,
const Node&, size_t) {
return DummyState{}; },
747 [&upfn](DummyState,
const Node&
node, std::span<Result>
subs) {
749 return std::optional<Result>(std::move(res));
757 std::vector<std::pair<const Node<Key>&,
const Node<Key>&>> queue;
758 queue.emplace_back(node1, node2);
759 while (!queue.empty()) {
760 const auto& [a, b] = queue.back();
762 if (std::tie(a.fragment, a.k, a.keys, a.data) < std::tie(b.fragment, b.k, b.keys, b.data))
return -1;
763 if (std::tie(b.fragment, b.k, b.keys, b.data) < std::tie(a.fragment, a.k, a.keys, a.data))
return 1;
764 if (a.subs.size() < b.subs.size())
return -1;
765 if (b.subs.size() < a.subs.size())
return 1;
766 size_t n = a.
subs.size();
767 for (
size_t i = 0; i < n; ++i) {
768 queue.emplace_back(a.subs[n - 1 - i], b.subs[n - 1 - i]);
776 using namespace internal;
779 std::vector<Type> sub_types;
781 for (
const auto& sub :
subs) sub_types.push_back(sub.GetType());
792 template<
typename Ctx>
811 switch (
node.fragment) {
825 if (
node.subs[0].GetType() <<
"x"_mst) {
828 return std::move(
subs[0]);
845 for (
const auto& key :
node.keys) {
853 for (
auto it =
node.keys.begin() + 1; it !=
node.keys.end(); ++it) {
860 for (
size_t i = 1; i <
subs.size(); ++i) {
868 return TreeEval<CScript>(
false, downfn, upfn);
871 template<
typename CTx>
872 std::optional<std::string>
ToString(
const CTx& ctx)
const {
877 template<
typename CTx>
878 std::optional<std::string>
ToString(
const CTx& ctx,
bool& has_priv_key)
const {
882 auto downfn = [](bool,
const Node&
node, size_t) {
891 auto toString = [&ctx, &has_priv_key](Key key) -> std::optional<std::string> {
892 bool fragment_has_priv_key{
false};
893 auto key_str{ctx.ToString(key, fragment_has_priv_key)};
894 if (key_str) has_priv_key = has_priv_key || fragment_has_priv_key;
900 auto upfn = [is_tapscript, &toString](
bool wrapped,
const Node&
node, std::span<std::string>
subs) -> std::optional<std::string> {
901 std::string
ret = wrapped ?
":" :
"";
903 switch (
node.fragment) {
909 auto key_str = toString(
node.subs[0].keys[0]);
910 if (!key_str)
return {};
911 return std::move(
ret) +
"pk(" + std::move(*key_str) +
")";
915 auto key_str = toString(
node.subs[0].keys[0]);
916 if (!key_str)
return {};
917 return std::move(
ret) +
"pkh(" + std::move(*key_str) +
")";
919 return "c" + std::move(
subs[0]);
934 switch (
node.fragment) {
936 auto key_str = toString(
node.keys[0]);
937 if (!key_str)
return {};
938 return std::move(
ret) +
"pk_k(" + std::move(*key_str) +
")";
941 auto key_str = toString(
node.keys[0]);
942 if (!key_str)
return {};
943 return std::move(
ret) +
"pk_h(" + std::move(*key_str) +
")";
962 return std::move(
ret) +
"andor(" + std::move(
subs[0]) +
"," + std::move(
subs[1]) +
"," + std::move(
subs[2]) +
")";
966 for (
const auto& key :
node.keys) {
967 auto key_str = toString(key);
968 if (!key_str)
return {};
969 str +=
"," + std::move(*key_str);
971 return std::move(str) +
")";
976 for (
const auto& key :
node.keys) {
977 auto key_str = toString(key);
978 if (!key_str)
return {};
979 str +=
"," + std::move(*key_str);
981 return std::move(str) +
")";
985 for (
auto& sub :
subs) {
986 str +=
"," + std::move(sub);
988 return std::move(str) +
")";
995 return TreeEvalMaybe<std::string>(
false, downfn, upfn);
1013 const auto count{1 +
subs[0].ops.count +
subs[1].ops.count};
1014 const auto sat{
subs[0].ops.sat +
subs[1].ops.sat};
1015 const auto dsat{
subs[0].ops.dsat +
subs[1].ops.dsat};
1016 return {
count, sat, dsat};
1019 const auto count{1 +
subs[0].ops.count +
subs[1].ops.count};
1021 const auto dsat{
subs[0].ops.dsat +
subs[1].ops.dsat};
1022 return {
count, sat, dsat};
1025 const auto count{3 +
subs[0].ops.count +
subs[1].ops.count};
1026 const auto sat{
subs[0].ops.sat | (
subs[1].ops.sat +
subs[0].ops.dsat)};
1027 const auto dsat{
subs[0].ops.dsat +
subs[1].ops.dsat};
1028 return {
count, sat, dsat};
1031 const auto count{2 +
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 return {
count, sat, {}};
1036 const auto count{3 +
subs[0].ops.count +
subs[1].ops.count};
1037 const auto sat{
subs[0].ops.sat |
subs[1].ops.sat};
1038 const auto dsat{
subs[0].ops.dsat |
subs[1].ops.dsat};
1039 return {
count, sat, dsat};
1042 const auto count{3 +
subs[0].ops.count +
subs[1].ops.count +
subs[2].ops.count};
1044 const auto dsat{
subs[0].ops.dsat +
subs[2].ops.dsat};
1045 return {
count, sat, dsat};
1059 for (
const auto& sub :
subs) {
1060 count += sub.ops.count + 1;
1061 auto next_sats =
Vector(sats[0] + sub.ops.dsat);
1062 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub.ops.dsat) | (sats[j - 1] + sub.ops.sat));
1063 next_sats.push_back(sats[sats.size() - 1] + sub.ops.sat);
1064 sats = std::move(next_sats);
1067 return {
count, sats[
k], sats[0]};
1074 using namespace internal;
1090 const auto& x{subs[0].ss};
1091 const auto& y{subs[1].ss};
1092 const auto& z{subs[2].ss};
1094 (x.Sat() + SatInfo::If() + y.Sat()) | (x.Dsat() + SatInfo::If() + z.Sat()),
1095 x.Dsat() + SatInfo::If() + z.Dsat()
1099 const auto& x{subs[0].ss};
1100 const auto& y{subs[1].ss};
1101 return {x.Sat() + y.Sat(), {}};
1104 const auto& x{subs[0].ss};
1105 const auto& y{subs[1].ss};
1106 return {x.Sat() + y.Sat() + SatInfo::BinaryOp(), x.Dsat() + y.Dsat() + SatInfo::BinaryOp()};
1109 const auto& x{subs[0].ss};
1110 const auto& y{subs[1].ss};
1112 ((x.Sat() + y.Dsat()) | (x.Dsat() + y.Sat())) + SatInfo::BinaryOp(),
1113 x.Dsat() + y.Dsat() + SatInfo::BinaryOp()
1117 const auto& x{subs[0].ss};
1118 const auto& y{subs[1].ss};
1119 return {(x.Sat() + SatInfo::If()) | (x.Dsat() + SatInfo::If() + y.Sat()), {}};
1122 const auto& x{subs[0].ss};
1123 const auto& y{subs[1].ss};
1130 const auto& x{subs[0].ss};
1131 const auto& y{subs[1].ss};
1132 return {SatInfo::If() + (x.Sat() | y.Sat()), SatInfo::If() + (x.Dsat() | y.Dsat())};
1161 auto sats =
Vector(SatInfo::Empty());
1162 for (
size_t i = 0; i < subs.size(); ++i) {
1165 auto add = i ? SatInfo::BinaryOp() : SatInfo::Empty();
1167 auto next_sats =
Vector(sats[0] + subs[i].ss.Dsat() + add);
1169 for (
size_t j = 1; j < sats.size(); ++j) {
1170 next_sats.push_back(((sats[j] + subs[i].ss.Dsat()) | (sats[j - 1] + subs[i].ss.Sat())) + add);
1173 next_sats.push_back(sats[sats.size() - 1] + subs[i].ss.Sat() + add);
1175 sats = std::move(next_sats);
1190 const uint32_t pubkey_size =
IsTapscript(m_script_ctx) ? 1 + 32 : 1 + 33;
1203 const auto sat{(subs[0].ws.sat + subs[1].ws.sat) | (subs[0].ws.dsat + subs[2].ws.sat)};
1204 const auto dsat{subs[0].ws.dsat + subs[2].ws.dsat};
1208 case Fragment::AND_B:
return {subs[0].ws.sat + subs[1].ws.sat, subs[0].ws.dsat + subs[1].ws.dsat};
1210 const auto sat{(subs[0].ws.dsat + subs[1].ws.sat) | (subs[0].ws.sat + subs[1].ws.dsat)};
1211 const auto dsat{subs[0].ws.dsat + subs[1].ws.dsat};
1214 case Fragment::OR_C:
return {subs[0].ws.sat | (subs[0].ws.dsat + subs[1].ws.sat), {}};
1215 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};
1216 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)};
1228 for (
const auto& sub : subs) {
1229 auto next_sats =
Vector(sats[0] + sub.ws.dsat);
1230 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub.ws.dsat) | (sats[j - 1] + sub.ws.sat));
1231 next_sats.push_back(sats[sats.size() - 1] + sub.ws.sat);
1232 sats = std::move(next_sats);
1235 return {sats[
k], sats[0]};
1241 template<
typename Ctx>
1243 using namespace internal;
1247 auto helper = [&ctx](
const Node&
node, std::span<InputResult> subres) -> InputResult {
1248 switch (
node.fragment) {
1250 std::vector<unsigned char> sig;
1252 return {
ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)};
1255 std::vector<unsigned char> key = ctx.ToPKBytes(
node.keys[0]), sig;
1257 return {
ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)};
1263 for (
size_t i = 0; i <
node.keys.size(); ++i) {
1266 std::vector<unsigned char> sig;
1269 auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1273 std::vector<InputStack> next_sats;
1274 next_sats.push_back(sats[0] +
ZERO);
1275 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] +
ZERO) | (std::move(sats[j - 1]) + sat));
1276 next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1278 sats = std::move(next_sats);
1282 auto& nsat{sats[0]};
1285 return {std::move(nsat), std::move(sats[
node.k])};
1292 for (
size_t i = 0; i <
node.keys.size(); ++i) {
1293 std::vector<unsigned char> sig;
1296 auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail);
1300 std::vector<InputStack> next_sats;
1301 next_sats.push_back(sats[0]);
1302 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back(sats[j] | (std::move(sats[j - 1]) + sat));
1303 next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat));
1305 sats = std::move(next_sats);
1308 InputStack nsat =
ZERO;
1309 for (
size_t i = 0; i <
node.k; ++i) nsat = std::move(nsat) +
ZERO;
1311 return {std::move(nsat), std::move(sats[
node.k])};
1318 for (
size_t i = 0; i < subres.size(); ++i) {
1320 auto& res = subres[subres.size() - i - 1];
1324 std::vector<InputStack> next_sats;
1325 next_sats.push_back(sats[0] + res.nsat);
1326 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + res.nsat) | (std::move(sats[j - 1]) + res.sat));
1327 next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(res.sat));
1329 sats = std::move(next_sats);
1333 InputStack nsat = INVALID;
1334 for (
size_t i = 0; i < sats.size(); ++i) {
1341 if (i != 0 && i !=
node.k) sats[i].SetMalleable().SetNonCanon();
1343 if (i !=
node.k) nsat = std::move(nsat) | std::move(sats[i]);
1346 return {std::move(nsat), std::move(sats[
node.k])};
1349 return {INVALID, ctx.CheckOlder(
node.k) ?
EMPTY : INVALID};
1352 return {INVALID, ctx.CheckAfter(
node.k) ?
EMPTY : INVALID};
1355 std::vector<unsigned char> preimage;
1357 return {
ZERO32, InputStack(std::move(preimage)).SetAvailable(avail)};
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 auto& x = subres[0], &y = subres[1];
1382 return {(y.nsat + x.sat).SetNonCanon(), y.sat + x.sat};
1385 auto& x = subres[0], &y = subres[1];
1391 return {(y.nsat + x.nsat) | (y.sat + x.nsat).SetMalleable().SetNonCanon() | (y.nsat + x.sat).SetMalleable().SetNonCanon(), y.sat + x.sat};
1394 auto& x = subres[0], &z = subres[1];
1396 return {z.nsat + x.nsat, (z.nsat + x.sat) | (z.sat + x.nsat) | (z.sat + x.sat).SetMalleable().SetNonCanon()};
1399 auto& x = subres[0], &z = subres[1];
1400 return {INVALID, std::move(x.sat) | (z.sat + x.nsat)};
1403 auto& x = subres[0], &z = subres[1];
1404 return {z.nsat + x.nsat, std::move(x.sat) | (z.sat + x.nsat)};
1407 auto& x = subres[0], &z = subres[1];
1408 return {(x.nsat + ONE) | (z.nsat +
ZERO), (x.sat + ONE) | (z.sat +
ZERO)};
1411 auto& x = subres[0], &y = subres[1], &z = subres[2];
1412 return {(y.nsat + x.sat).SetNonCanon() | (z.nsat + x.nsat), (y.sat + x.sat) | (z.sat + x.nsat)};
1418 return std::move(subres[0]);
1420 auto &x = subres[0];
1421 return {
ZERO, x.sat + ONE};
1424 auto &x = subres[0];
1430 return {InputStack(
ZERO).SetMalleable(x.nsat.available !=
Availability::NO && !x.nsat.has_sig), std::move(x.sat)};
1433 auto &x = subres[0];
1434 return {INVALID, std::move(x.sat)};
1440 return {INVALID, INVALID};
1443 auto tester = [&helper](
const Node&
node, std::span<InputResult> subres) -> InputResult {
1444 auto ret = helper(
node, subres);
1486 return TreeEval<InputResult>(tester);
1501 Comp(
const Ctx& ctx) : ctx_ptr(&ctx) {}
1502 bool operator()(
const Key& a,
const Key& b)
const {
return ctx_ptr->KeyCompare(a, b); }
1508 using keyset = std::set<Key, Comp>;
1509 using state = std::optional<keyset>;
1511 auto upfn = [&ctx](
const Node&
node, std::span<state> subs) -> state {
1513 if (
node.has_duplicate_keys.has_value() && *
node.has_duplicate_keys)
return {};
1516 for (
auto& sub : subs) {
1517 if (!sub.has_value()) {
1518 node.has_duplicate_keys =
true;
1525 size_t keys_count =
node.keys.size();
1526 keyset key_set{
node.keys.begin(),
node.keys.end(), Comp(ctx)};
1527 if (key_set.size() != keys_count) {
1529 node.has_duplicate_keys =
true;
1534 for (
auto& sub : subs) {
1535 keys_count += sub->size();
1538 if (key_set.size() < sub->size()) std::swap(key_set, *sub);
1539 key_set.merge(*sub);
1540 if (key_set.size() != keys_count) {
1541 node.has_duplicate_keys =
true;
1546 node.has_duplicate_keys =
false;
1550 TreeEval<state>(upfn);
1558 if (!ops.sat.Valid())
return {};
1559 return ops.count + ops.sat.Value();
1574 return !((GetType() &
"BKW"_mst) ==
""_mst);
1579 if (!ss.Sat().Valid())
return {};
1580 return ss.Sat().NetDiff() +
static_cast<int32_t
>(IsBKW());
1585 if (!ss.Sat().Valid())
return {};
1586 return ss.Sat().Exec() +
static_cast<int32_t
>(IsBKW());
1594 if (
const auto exec_ss = GetExecStackSize())
return exec_ss <=
MAX_STACK_SIZE;
1607 if (!ws.sat.Valid())
return {};
1608 return ws.sat.Value();
1619 return TreeEval<const Node*>([](
const Node&
node, std::span<const Node*> subs) ->
const Node* {
1620 for (
auto& sub: subs)
if (sub)
return sub;
1621 if (!
node.IsSaneSubexpression())
return &
node;
1628 template<
typename F>
1632 return TreeEval<int>([&fn](
const Node&
node, std::span<int> subs) ->
bool {
1633 switch (
node.fragment) {
1634 case Fragment::JUST_0:
1636 case Fragment::JUST_1:
1638 case Fragment::PK_K:
1639 case Fragment::PK_H:
1640 case Fragment::MULTI:
1641 case Fragment::MULTI_A:
1642 case Fragment::AFTER:
1643 case Fragment::OLDER:
1644 case Fragment::HASH256:
1645 case Fragment::HASH160:
1646 case Fragment::SHA256:
1647 case Fragment::RIPEMD160:
1648 return bool{fn(node)};
1650 return (subs[0] && subs[1]) || subs[2];
1653 return subs[0] && subs[1];
1658 return subs[0] || subs[1];
1660 return static_cast<uint32_t
>(
std::count(subs.begin(), subs.end(),
true)) >=
node.k;
1662 assert(subs.size() >= 1);
1671 if (GetType() ==
""_mst)
return false;
1694 bool IsSaneSubexpression()
const {
return ValidSatisfactions() && IsNonMalleable() && CheckTimeLocksMix() && CheckDuplicateKey(); }
1697 bool IsSane()
const {
return IsValidTopLevel() && IsSaneSubexpression() && NeedsSignature(); }
1703 template<
typename Ctx>
1704 Availability Satisfy(
const Ctx& ctx, std::vector<std::vector<unsigned char>>& stack,
bool nonmalleable =
true)
const {
1705 auto ret = ProduceInput(ctx);
1706 if (nonmalleable && (
ret.sat.malleable || !
ret.sat.has_sig))
return Availability::NO;
1707 stack = std::move(
ret.sat.stack);
1708 return ret.sat.available;
1716 : 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()) {}
1718 : fragment(nt),
k(val),
data(
std::move(arg)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1720 : 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()) {}
1722 : fragment(nt),
k(val), keys(
std::move(key)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1724 : fragment(nt),
k(val), subs(
std::move(sub)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1726 : fragment(nt),
k(val), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1729 template <
typename Ctx>
Node(
const Ctx& ctx,
enum Fragment nt, std::vector<Node> sub, std::vector<unsigned char> arg, uint32_t val = 0)
1730 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(sub),
std::move(arg), val) { DuplicateKeyCheck(ctx); }
1731 template <
typename Ctx>
Node(
const Ctx& ctx,
enum Fragment nt, std::vector<unsigned char> arg, uint32_t val = 0)
1732 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(arg), val) { DuplicateKeyCheck(ctx);}
1733 template <
typename Ctx>
Node(
const Ctx& ctx,
enum Fragment nt, std::vector<Node> sub, std::vector<Key> key, uint32_t val = 0)
1734 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(sub),
std::move(key), val) { DuplicateKeyCheck(ctx); }
1735 template <
typename Ctx>
Node(
const Ctx& ctx,
enum Fragment nt, std::vector<Key> key, uint32_t val = 0)
1736 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(key), val) { DuplicateKeyCheck(ctx); }
1737 template <
typename Ctx>
Node(
const Ctx& ctx,
enum Fragment nt, std::vector<Node> sub, uint32_t val = 0)
1738 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt,
std::move(sub), val) { DuplicateKeyCheck(ctx); }
1739 template <
typename Ctx>
Node(
const Ctx& ctx,
enum Fragment nt, uint32_t val = 0)
1740 :
Node(internal::NoDupCheck{}, ctx.MsContext(), nt, val) { DuplicateKeyCheck(ctx); }
1810template<
typename Key,
typename Ctx>
1811std::optional<std::pair<Key, int>>
ParseKeyEnd(std::span<const char> in,
const Ctx& ctx)
1814 if (key_size < 1)
return {};
1815 auto key = ctx.FromString(in.begin(), in.begin() + key_size);
1816 if (!key)
return {};
1817 return {{std::move(*key), key_size}};
1821template<
typename Ctx>
1822std::optional<std::pair<std::vector<unsigned char>,
int>>
ParseHexStrEnd(std::span<const char> in,
const size_t expected_size,
1826 if (hash_size < 1)
return {};
1827 std::string val = std::string(in.begin(), in.begin() + hash_size);
1828 if (!
IsHex(val))
return {};
1830 if (hash.size() != expected_size)
return {};
1831 return {{std::move(hash), hash_size}};
1835template<
typename Key>
1838 Node<Key> child{std::move(constructed.back())};
1839 constructed.pop_back();
1852template <
typename Key,
typename Ctx>
1853inline std::optional<Node<Key>>
Parse(std::span<const char> in,
const Ctx& ctx)
1867 size_t script_size{1};
1871 std::vector<std::tuple<ParseContext, int64_t, int64_t>> to_parse;
1872 std::vector<Node<Key>> constructed;
1874 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
1877 const auto parse_multi_exp = [&](std::span<const char>& in,
const bool is_multi_a) ->
bool {
1879 const auto required_ctx{is_multi_a ? MiniscriptContext::TAPSCRIPT : MiniscriptContext::P2WSH};
1880 if (ctx.MsContext() != required_ctx)
return false;
1883 if (next_comma < 1)
return false;
1884 const auto k_to_integral{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
1885 if (!k_to_integral.has_value())
return false;
1886 const int64_t
k{k_to_integral.value()};
1887 in = in.subspan(next_comma + 1);
1889 std::vector<Key> keys;
1890 while (next_comma != -1) {
1892 int key_length = (next_comma == -1) ?
FindNextChar(in,
')') : next_comma;
1893 if (key_length < 1)
return false;
1894 auto key = ctx.FromString(in.begin(), in.begin() + key_length);
1895 if (!key)
return false;
1896 keys.push_back(std::move(*key));
1897 in = in.subspan(key_length + 1);
1899 if (keys.size() < 1 || keys.size() > max_keys)
return false;
1900 if (k < 1 || k > (int64_t)keys.size())
return false;
1904 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys),
k);
1906 script_size += 2 + (keys.size() > 16) + (
k > 16) + 34 * keys.size();
1907 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys),
k);
1912 while (!to_parse.empty()) {
1913 if (script_size > max_size)
return {};
1916 auto [cur_context, n,
k] = to_parse.back();
1917 to_parse.pop_back();
1919 switch (cur_context) {
1920 case ParseContext::WRAPPED_EXPR: {
1921 std::optional<size_t> colon_index{};
1922 for (
size_t i = 1; i < in.size(); ++i) {
1927 if (in[i] <
'a' || in[i] >
'z')
break;
1930 bool last_was_v{
false};
1931 for (
size_t j = 0; colon_index && j < *colon_index; ++j) {
1932 if (script_size > max_size)
return {};
1935 to_parse.emplace_back(ParseContext::ALT, -1, -1);
1936 }
else if (in[j] ==
's') {
1938 to_parse.emplace_back(ParseContext::SWAP, -1, -1);
1939 }
else if (in[j] ==
'c') {
1942 }
else if (in[j] ==
'd') {
1944 to_parse.emplace_back(ParseContext::DUP_IF, -1, -1);
1945 }
else if (in[j] ==
'j') {
1947 to_parse.emplace_back(ParseContext::NON_ZERO, -1, -1);
1948 }
else if (in[j] ==
'n') {
1950 to_parse.emplace_back(ParseContext::ZERO_NOTEQUAL, -1, -1);
1951 }
else if (in[j] ==
'v') {
1954 if (last_was_v)
return {};
1955 to_parse.emplace_back(ParseContext::VERIFY, -1, -1);
1956 }
else if (in[j] ==
'u') {
1958 to_parse.emplace_back(ParseContext::WRAP_U, -1, -1);
1959 }
else if (in[j] ==
't') {
1961 to_parse.emplace_back(ParseContext::WRAP_T, -1, -1);
1962 }
else if (in[j] ==
'l') {
1966 to_parse.emplace_back(ParseContext::OR_I, -1, -1);
1970 last_was_v = (in[j] ==
'v');
1972 to_parse.emplace_back(ParseContext::EXPR, -1, -1);
1973 if (colon_index) in = in.subspan(*colon_index + 1);
1976 case ParseContext::EXPR: {
1977 if (
Const(
"0", in)) {
1979 }
else if (
Const(
"1", in)) {
1981 }
else if (
Const(
"pk(", in)) {
1982 auto res = ParseKeyEnd<Key, Ctx>(in, ctx);
1983 if (!res)
return {};
1984 auto& [key, key_size] = *res;
1986 in = in.subspan(key_size + 1);
1987 script_size +=
IsTapscript(ctx.MsContext()) ? 33 : 34;
1988 }
else if (
Const(
"pkh(", in)) {
1989 auto res = ParseKeyEnd<Key>(in, ctx);
1990 if (!res)
return {};
1991 auto& [key, key_size] = *res;
1993 in = in.subspan(key_size + 1);
1995 }
else if (
Const(
"pk_k(", in)) {
1996 auto res = ParseKeyEnd<Key>(in, ctx);
1997 if (!res)
return {};
1998 auto& [key, key_size] = *res;
2000 in = in.subspan(key_size + 1);
2001 script_size +=
IsTapscript(ctx.MsContext()) ? 32 : 33;
2002 }
else if (
Const(
"pk_h(", in)) {
2003 auto res = ParseKeyEnd<Key>(in, ctx);
2004 if (!res)
return {};
2005 auto& [key, key_size] = *res;
2007 in = in.subspan(key_size + 1);
2009 }
else if (
Const(
"sha256(", in)) {
2011 if (!res)
return {};
2012 auto& [hash, hash_size] = *res;
2013 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, std::move(hash));
2014 in = in.subspan(hash_size + 1);
2016 }
else if (
Const(
"ripemd160(", in)) {
2018 if (!res)
return {};
2019 auto& [hash, hash_size] = *res;
2021 in = in.subspan(hash_size + 1);
2023 }
else if (
Const(
"hash256(", in)) {
2025 if (!res)
return {};
2026 auto& [hash, hash_size] = *res;
2027 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, std::move(hash));
2028 in = in.subspan(hash_size + 1);
2030 }
else if (
Const(
"hash160(", in)) {
2032 if (!res)
return {};
2033 auto& [hash, hash_size] = *res;
2034 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, std::move(hash));
2035 in = in.subspan(hash_size + 1);
2037 }
else if (
Const(
"after(", in)) {
2039 if (arg_size < 1)
return {};
2040 const auto num{ToIntegral<int64_t>(std::string_view(in.data(), arg_size))};
2041 if (!num.has_value() || *num < 1 || *num >= 0x80000000L)
return {};
2043 in = in.subspan(arg_size + 1);
2044 script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
2045 }
else if (
Const(
"older(", in)) {
2047 if (arg_size < 1)
return {};
2048 const auto num{ToIntegral<int64_t>(std::string_view(in.data(), arg_size))};
2049 if (!num.has_value() || *num < 1 || *num >= 0x80000000L)
return {};
2051 in = in.subspan(arg_size + 1);
2052 script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
2053 }
else if (
Const(
"multi(", in)) {
2054 if (!parse_multi_exp(in,
false))
return {};
2055 }
else if (
Const(
"multi_a(", in)) {
2056 if (!parse_multi_exp(in,
true))
return {};
2057 }
else if (
Const(
"thresh(", in)) {
2059 if (next_comma < 1)
return {};
2060 const auto k{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
2061 if (!
k.has_value() || *
k < 1)
return {};
2062 in = in.subspan(next_comma + 1);
2064 to_parse.emplace_back(ParseContext::THRESH, 1, *
k);
2065 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2066 script_size += 2 + (*
k > 16) + (*
k > 0x7f) + (*
k > 0x7fff) + (*
k > 0x7fffff);
2067 }
else if (
Const(
"andor(", in)) {
2068 to_parse.emplace_back(ParseContext::ANDOR, -1, -1);
2069 to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
2070 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2071 to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2072 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2073 to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2074 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2077 if (
Const(
"and_n(", in)) {
2078 to_parse.emplace_back(ParseContext::AND_N, -1, -1);
2080 }
else if (
Const(
"and_b(", in)) {
2081 to_parse.emplace_back(ParseContext::AND_B, -1, -1);
2083 }
else if (
Const(
"and_v(", in)) {
2084 to_parse.emplace_back(ParseContext::AND_V, -1, -1);
2086 }
else if (
Const(
"or_b(", in)) {
2087 to_parse.emplace_back(ParseContext::OR_B, -1, -1);
2089 }
else if (
Const(
"or_c(", in)) {
2090 to_parse.emplace_back(ParseContext::OR_C, -1, -1);
2092 }
else if (
Const(
"or_d(", in)) {
2093 to_parse.emplace_back(ParseContext::OR_D, -1, -1);
2095 }
else if (
Const(
"or_i(", in)) {
2096 to_parse.emplace_back(ParseContext::OR_I, -1, -1);
2101 to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1);
2102 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2103 to_parse.emplace_back(ParseContext::COMMA, -1, -1);
2104 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2108 case ParseContext::ALT: {
2112 case ParseContext::SWAP: {
2120 case ParseContext::DUP_IF: {
2124 case ParseContext::NON_ZERO: {
2128 case ParseContext::ZERO_NOTEQUAL: {
2132 case ParseContext::VERIFY: {
2133 script_size += (constructed.back().GetType() <<
"x"_mst);
2137 case ParseContext::WRAP_U: {
2138 constructed.back() =
Node{
internal::NoDupCheck{}, ctx.MsContext(), Fragment::OR_I,
Vector(std::move(constructed.back()),
Node<Key>{internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0})};
2141 case ParseContext::WRAP_T: {
2142 constructed.back() =
Node{
internal::NoDupCheck{}, ctx.MsContext(), Fragment::AND_V,
Vector(std::move(constructed.back()),
Node<Key>{internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1})};
2145 case ParseContext::AND_B: {
2146 BuildBack(ctx.MsContext(), Fragment::AND_B, constructed);
2149 case ParseContext::AND_N: {
2150 auto mid = std::move(constructed.back());
2151 constructed.pop_back();
2152 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})};
2155 case ParseContext::AND_V: {
2156 BuildBack(ctx.MsContext(), Fragment::AND_V, constructed);
2159 case ParseContext::OR_B: {
2160 BuildBack(ctx.MsContext(), Fragment::OR_B, constructed);
2163 case ParseContext::OR_C: {
2164 BuildBack(ctx.MsContext(), Fragment::OR_C, constructed);
2167 case ParseContext::OR_D: {
2168 BuildBack(ctx.MsContext(), Fragment::OR_D, constructed);
2171 case ParseContext::OR_I: {
2172 BuildBack(ctx.MsContext(), Fragment::OR_I, constructed);
2175 case ParseContext::ANDOR: {
2176 auto right = std::move(constructed.back());
2177 constructed.pop_back();
2178 auto mid = std::move(constructed.back());
2179 constructed.pop_back();
2180 constructed.back() = Node{internal::NoDupCheck{}, ctx.MsContext(), Fragment::ANDOR,
Vector(std::move(constructed.back()), std::move(mid), std::move(right))};
2183 case ParseContext::THRESH: {
2184 if (in.size() < 1)
return {};
2187 to_parse.emplace_back(ParseContext::THRESH, n+1, k);
2188 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2190 }
else if (in[0] ==
')') {
2191 if (k > n)
return {};
2194 std::vector<Node<Key>> subs;
2195 for (
int i = 0; i < n; ++i) {
2196 subs.push_back(std::move(constructed.back()));
2197 constructed.pop_back();
2199 std::reverse(subs.begin(), subs.end());
2200 constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs), k);
2206 case ParseContext::COMMA: {
2207 if (in.size() < 1 || in[0] !=
',')
return {};
2211 case ParseContext::CLOSE_BRACKET: {
2212 if (in.size() < 1 || in[0] !=
')')
return {};
2220 assert(constructed.size() >= 1);
2222 assert(constructed[0].ScriptSize() == script_size);
2223 if (in.size() > 0)
return {};
2224 Node<Key> tl_node{std::move(constructed.front())};
2225 tl_node.DuplicateKeyCheck(ctx);
2311template <
typename Key,
typename Ctx,
typename I>
2315 std::vector<std::tuple<DecodeContext, int64_t, int64_t>> to_parse;
2316 std::vector<Node<Key>> constructed;
2320 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2322 while (!to_parse.empty()) {
2324 if (!constructed.empty() && !constructed.back().IsValid())
return {};
2327 auto [cur_context, n,
k] = to_parse.back();
2328 to_parse.pop_back();
2330 switch(cur_context) {
2331 case DecodeContext::SINGLE_BKV_EXPR: {
2332 if (in >= last)
return {};
2335 if (in[0].first ==
OP_1) {
2340 if (in[0].first ==
OP_0) {
2346 if (in[0].second.size() == 33 || in[0].second.size() == 32) {
2347 auto key = ctx.FromPKBytes(in[0].second.begin(), in[0].second.end());
2348 if (!key)
return {};
2354 auto key = ctx.FromPKHBytes(in[2].second.begin(), in[2].second.end());
2355 if (!key)
return {};
2361 std::optional<int64_t> num;
2364 if (*num < 1 || *num > 0x7FFFFFFFL)
return {};
2370 if (num < 1 || num > 0x7FFFFFFFL)
return {};
2376 if (in[2].first ==
OP_SHA256 && in[1].second.size() == 32) {
2377 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::SHA256, in[1].second);
2380 }
else if (in[2].first ==
OP_RIPEMD160 && in[1].second.size() == 20) {
2384 }
else if (in[2].first ==
OP_HASH256 && in[1].second.size() == 32) {
2385 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH256, in[1].second);
2388 }
else if (in[2].first ==
OP_HASH160 && in[1].second.size() == 20) {
2389 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::HASH160, in[1].second);
2397 std::vector<Key> keys;
2399 if (!n || last - in < 3 + *n)
return {};
2400 if (*n < 1 || *n > 20)
return {};
2401 for (
int i = 0; i < *n; ++i) {
2402 if (in[2 + i].second.size() != 33)
return {};
2403 auto key = ctx.FromPKBytes(in[2 + i].second.begin(), in[2 + i].second.end());
2404 if (!key)
return {};
2405 keys.push_back(std::move(*key));
2408 if (!
k || *k < 1 || *k > *n)
return {};
2410 std::reverse(keys.begin(), keys.end());
2411 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), *
k);
2415 if (last - in >= 4 && in[0].first ==
OP_NUMEQUAL) {
2421 if (last - in < 2 + *
k * 2)
return {};
2422 std::vector<Key> keys;
2425 for (
int pos = 2;; pos += 2) {
2426 if (last - in < pos + 2)
return {};
2429 if (in[pos + 1].second.size() != 32)
return {};
2430 auto key = ctx.FromPKBytes(in[pos + 1].second.begin(), in[pos + 1].second.end());
2431 if (!key)
return {};
2432 keys.push_back(std::move(*key));
2438 if (keys.size() < (
size_t)*
k)
return {};
2439 in += 2 + keys.size() * 2;
2440 std::reverse(keys.begin(), keys.end());
2441 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), *
k);
2451 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2457 to_parse.emplace_back(DecodeContext::VERIFY, -1, -1);
2458 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2464 to_parse.emplace_back(DecodeContext::ZERO_NOTEQUAL, -1, -1);
2465 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2470 if (*num < 1)
return {};
2472 to_parse.emplace_back(DecodeContext::THRESH_W, 0, *num);
2478 to_parse.emplace_back(DecodeContext::ENDIF, -1, -1);
2479 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2490 to_parse.emplace_back(DecodeContext::AND_B, -1, -1);
2491 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2492 to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2498 to_parse.emplace_back(DecodeContext::OR_B, -1, -1);
2499 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2500 to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2506 case DecodeContext::BKV_EXPR: {
2507 to_parse.emplace_back(DecodeContext::MAYBE_AND_V, -1, -1);
2508 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2511 case DecodeContext::W_EXPR: {
2513 if (in >= last)
return {};
2516 to_parse.emplace_back(DecodeContext::ALT, -1, -1);
2518 to_parse.emplace_back(DecodeContext::SWAP, -1, -1);
2520 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2523 case DecodeContext::MAYBE_AND_V: {
2527 to_parse.emplace_back(DecodeContext::AND_V, -1, -1);
2529 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2533 case DecodeContext::SWAP: {
2534 if (in >= last || in[0].first !=
OP_SWAP || constructed.empty())
return {};
2539 case DecodeContext::ALT: {
2540 if (in >= last || in[0].first !=
OP_TOALTSTACK || constructed.empty())
return {};
2546 if (constructed.empty())
return {};
2550 case DecodeContext::DUP_IF: {
2551 if (constructed.empty())
return {};
2555 case DecodeContext::VERIFY: {
2556 if (constructed.empty())
return {};
2560 case DecodeContext::NON_ZERO: {
2561 if (constructed.empty())
return {};
2565 case DecodeContext::ZERO_NOTEQUAL: {
2566 if (constructed.empty())
return {};
2570 case DecodeContext::AND_V: {
2571 if (constructed.size() < 2)
return {};
2572 BuildBack(ctx.MsContext(), Fragment::AND_V, constructed,
true);
2575 case DecodeContext::AND_B: {
2576 if (constructed.size() < 2)
return {};
2577 BuildBack(ctx.MsContext(), Fragment::AND_B, constructed,
true);
2580 case DecodeContext::OR_B: {
2581 if (constructed.size() < 2)
return {};
2582 BuildBack(ctx.MsContext(), Fragment::OR_B, constructed,
true);
2585 case DecodeContext::OR_C: {
2586 if (constructed.size() < 2)
return {};
2587 BuildBack(ctx.MsContext(), Fragment::OR_C, constructed,
true);
2590 case DecodeContext::OR_D: {
2591 if (constructed.size() < 2)
return {};
2592 BuildBack(ctx.MsContext(), Fragment::OR_D, constructed,
true);
2595 case DecodeContext::ANDOR: {
2596 if (constructed.size() < 3)
return {};
2597 Node left{std::move(constructed.back())};
2598 constructed.pop_back();
2599 Node right{std::move(constructed.back())};
2600 constructed.pop_back();
2601 Node mid{std::move(constructed.back())};
2605 case DecodeContext::THRESH_W: {
2606 if (in >= last)
return {};
2607 if (in[0].first ==
OP_ADD) {
2609 to_parse.emplace_back(DecodeContext::THRESH_W, n+1,
k);
2610 to_parse.emplace_back(DecodeContext::W_EXPR, -1, -1);
2612 to_parse.emplace_back(DecodeContext::THRESH_E, n+1,
k);
2614 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2618 case DecodeContext::THRESH_E: {
2619 if (k < 1 || k > n || constructed.size() <
static_cast<size_t>(n))
return {};
2620 std::vector<Node<Key>> subs;
2621 for (
int i = 0; i < n; ++i) {
2622 Node sub{std::move(constructed.back())};
2623 constructed.pop_back();
2624 subs.push_back(std::move(sub));
2626 constructed.emplace_back(
internal::NoDupCheck{}, ctx.MsContext(), Fragment::THRESH, std::move(subs),
k);
2629 case DecodeContext::ENDIF: {
2630 if (in >= last)
return {};
2635 to_parse.emplace_back(DecodeContext::ENDIF_ELSE, -1, -1);
2636 to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1);
2639 else if (in[0].first ==
OP_IF) {
2640 if (last - in >= 2 && in[1].first ==
OP_DUP) {
2642 to_parse.emplace_back(DecodeContext::DUP_IF, -1, -1);
2645 to_parse.emplace_back(DecodeContext::NON_ZERO, -1, -1);
2651 }
else if (in[0].first ==
OP_NOTIF) {
2653 to_parse.emplace_back(DecodeContext::ENDIF_NOTIF, -1, -1);
2660 case DecodeContext::ENDIF_NOTIF: {
2661 if (in >= last)
return {};
2664 to_parse.emplace_back(DecodeContext::OR_D, -1, -1);
2666 to_parse.emplace_back(DecodeContext::OR_C, -1, -1);
2669 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2672 case DecodeContext::ENDIF_ELSE: {
2673 if (in >= last)
return {};
2674 if (in[0].first ==
OP_IF) {
2676 BuildBack(ctx.MsContext(), Fragment::OR_I, constructed,
true);
2677 }
else if (in[0].first ==
OP_NOTIF) {
2679 to_parse.emplace_back(DecodeContext::ANDOR, -1, -1);
2681 to_parse.emplace_back(DecodeContext::SINGLE_BKV_EXPR, -1, -1);
2689 if (constructed.size() != 1)
return {};
2690 Node tl_node{std::move(constructed.front())};
2694 if (!tl_node.IsValidTopLevel())
return {};
2700template <
typename Ctx>
2701inline std::optional<Node<typename Ctx::Key>>
FromString(
const std::string& str,
const Ctx& ctx)
2703 return internal::Parse<typename Ctx::Key>(str, ctx);
2706template <
typename Ctx>
2709 using namespace internal;
2713 if (!decomposed)
return {};
2714 auto it = decomposed->begin();
2715 auto ret = DecodeScript<typename Ctx::Key>(it, decomposed->end(), ctx);
2716 if (!
ret)
return {};
2717 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...
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.
std::optional< std::pair< std::vector< unsigned char >, int > > ParseHexStrEnd(std::span< const char > in, const size_t expected_size, const Ctx &ctx)
Parse a hex string ending at the end of the fragment's text representation.
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...
std::optional< std::pair< Key, int > > ParseKeyEnd(std::span< const char > in, const Ctx &ctx)
Parse a key string ending at the end of the fragment's text representation.
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)
bool Const(const std::string &str, std::span< const char > &sp, bool skip)
Parse a constant.
std::string ToString(const T &t)
Locale-independent version of std::to_string.
static constexpr unsigned int MAX_STANDARD_P2WSH_STACK_ITEMS
The maximum number of witness stack items in a standard P2WSH script.
static constexpr int32_t MAX_STANDARD_TX_WEIGHT
The maximum weight for transactions we're willing to relay/mine.
static constexpr unsigned int MAX_STANDARD_P2WSH_SCRIPT_SIZE
The maximum size in bytes of a standard witnessScript.
static constexpr unsigned int MAX_PUBKEYS_PER_MULTI_A
The limit of keys in OP_CHECKSIGADD-based scripts.
static const int MAX_STACK_SIZE
static const int MAX_OPS_PER_SCRIPT
CScript BuildScript(Ts &&... inputs)
Build a script by concatenating other scripts, or any argument accepted by CScript::operator<<.
static const int MAX_PUBKEYS_PER_MULTISIG
static bool verify(const CScriptNum10 &bignum, const CScriptNum &scriptnum)
constexpr unsigned int GetSizeOfCompactSize(uint64_t nSize)
Compact Size size < 253 – 1 byte size <= USHRT_MAX – 3 bytes (253 + 2 bytes) size <= UINT_MAX – 5 byt...
std::vector< Byte > ParseHex(std::string_view hex_str)
Like TryParseHex, but returns an empty vector on invalid input.
Ops(uint32_t in_count, MaxInt< uint32_t > in_sat, MaxInt< uint32_t > in_dsat)
MaxInt< uint32_t > sat
Number of keys in possibly executed OP_CHECKMULTISIG(VERIFY)s to satisfy.
MaxInt< uint32_t > dsat
Number of keys in possibly executed OP_CHECKMULTISIG(VERIFY)s to dissatisfy.
uint32_t count
Non-push opcodes.
MaxInt< uint32_t > sat
Maximum witness size to satisfy;.
MaxInt< uint32_t > dsat
Maximum witness size to dissatisfy;.
WitnessSize(MaxInt< uint32_t > in_sat, MaxInt< uint32_t > in_dsat)
static const std::vector< uint8_t > EMPTY
bool IsHex(std::string_view str)
std::vector< std::common_type_t< Args... > > Vector(Args &&... args)
Construct a vector with the specified elements.