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));
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 {};
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>
731 std::forward<DownFn>(downfn),
733 Result res{upfn(std::move(state),
node,
subs)};
734 return std::optional<Result>(std::move(res));
741 template<
typename Result,
typename UpFn>
744 struct 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]);
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) {
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) +
")";
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};
1020 const auto sat{(
subs[0].ops.sat +
subs[1].ops.dsat) | (
subs[1].
ops.sat +
subs[0].ops.dsat)};
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};
1043 const auto sat{(
subs[1].ops.sat +
subs[0].ops.sat) | (
subs[0].
ops.dsat +
subs[2].ops.sat)};
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]};
1081 case Fragment::PK_H:
return {SatInfo::OP_DUP() + SatInfo::Hash() + SatInfo::Push() + SatInfo::OP_EQUALVERIFY()};
1086 SatInfo::OP_SIZE() + SatInfo::Push() + SatInfo::OP_EQUALVERIFY() + SatInfo::Hash() + SatInfo::Push() + SatInfo::OP_EQUAL(),
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};
1125 (x.Sat() + SatInfo::OP_IFDUP(
true) + SatInfo::If()) | (x.Dsat() + SatInfo::OP_IFDUP(
false) + SatInfo::If() + y.Sat()),
1126 x.Dsat() + SatInfo::OP_IFDUP(
false) + SatInfo::If() + y.Dsat()
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())};
1147 subs[0].ss.Sat() + SatInfo::OP_CHECKSIG(),
1148 subs[0].ss.Dsat() + SatInfo::OP_CHECKSIG()
1151 SatInfo::OP_DUP() + SatInfo::If() +
subs[0].ss.Sat(),
1152 SatInfo::OP_DUP() + SatInfo::If()
1156 SatInfo::OP_SIZE() + SatInfo::OP_0NOTEQUAL() + SatInfo::If() +
subs[0].ss.Sat(),
1157 SatInfo::OP_SIZE() + SatInfo::OP_0NOTEQUAL() + SatInfo::If()
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);
1180 sats[
k] + SatInfo::Push() + SatInfo::OP_EQUAL(),
1181 sats[0] + SatInfo::Push() + SatInfo::OP_EQUAL()
1197 case Fragment::PK_H:
return {sig_size + pubkey_size, 1 + pubkey_size};
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};
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};
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>
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])};
1291 std::vector<InputStack> sats =
Vector(ZERO);
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);
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])};
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)};
1443 auto tester = [&helper](
const Node&
node, std::span<InputResult> subres) -> InputResult {
1444 auto ret = helper(
node, subres);
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;
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());
1607 if (!
ws.sat.Valid())
return {};
1608 return ws.sat.Value();
1620 for (
auto& sub:
subs)
if (sub)
return sub;
1621 if (!
node.IsSaneSubexpression())
return &
node;
1628 template<
typename F>
1633 switch (
node.fragment) {
1648 return bool{fn(
node)};
1660 return static_cast<uint32_t
>(std::count(
subs.begin(),
subs.end(),
true)) >=
node.k;
1671 if (
GetType() ==
""_mst)
return false;
1703 template<
typename Ctx>
1704 Availability Satisfy(
const Ctx& ctx, std::vector<std::vector<unsigned char>>& stack,
bool nonmalleable =
true)
const {
1707 stack = std::move(
ret.sat.stack);
1708 return ret.sat.available;
1729 template <
typename Ctx>
Node(
const Ctx& ctx,
enum Fragment nt, std::vector<Node> sub, std::vector<unsigned char> arg, uint32_t val = 0)
1731 template <
typename Ctx>
Node(
const Ctx& ctx,
enum Fragment nt, std::vector<unsigned char> arg, uint32_t val = 0)
1733 template <
typename Ctx>
Node(
const Ctx& ctx,
enum Fragment nt, std::vector<Node> sub, std::vector<Key> key, uint32_t val = 0)
1735 template <
typename Ctx>
Node(
const Ctx& ctx,
enum Fragment nt, std::vector<Key> key, uint32_t val = 0)
1737 template <
typename Ctx>
Node(
const Ctx& ctx,
enum Fragment nt, std::vector<Node> sub, uint32_t val = 0)
1739 template <
typename Ctx>
Node(
const Ctx& ctx,
enum Fragment nt, uint32_t val = 0)
1807int FindNextChar(std::span<const char> in,
char m);
1810template<
typename Key,
typename Ctx>
1811std::optional<Key>
ParseKey(
const std::string& func, std::span<const char>& in,
const Ctx& ctx)
1815 return ctx.FromString(expr);
1819template<
typename Ctx>
1820std::optional<std::vector<unsigned char>>
ParseHexStr(
const std::string& func, std::span<const char>& in,
const size_t expected_size,
1825 std::string val = std::string(expr.begin(), expr.end());
1826 if (!
IsHex(val))
return {};
1828 if (hash.size() != expected_size)
return {};
1833template<
typename Key>
1836 Node<Key> child{std::move(constructed.back())};
1837 constructed.pop_back();
1850template <
typename Key,
typename Ctx>
1851inline std::optional<Node<Key>>
Parse(std::span<const char> in,
const Ctx& ctx)
1865 size_t script_size{1};
1869 std::vector<std::tuple<ParseContext, int64_t, int64_t>> to_parse;
1870 std::vector<Node<Key>> constructed;
1875 const auto parse_multi_exp = [&](std::span<const char>& in,
const bool is_multi_a) ->
bool {
1878 if (ctx.MsContext() != required_ctx)
return false;
1881 if (next_comma < 1)
return false;
1883 if (!k_to_integral.has_value())
return false;
1884 const int64_t
k{k_to_integral.value()};
1885 in = in.subspan(next_comma + 1);
1887 std::vector<Key>
keys;
1888 while (next_comma != -1) {
1890 int key_length = (next_comma == -1) ?
FindNextChar(in,
')') : next_comma;
1891 if (key_length < 1)
return false;
1892 std::span<const char> sp{in.begin(), in.begin() + key_length};
1893 auto key = ctx.FromString(sp);
1894 if (!key)
return false;
1895 keys.push_back(std::move(*key));
1896 in = in.subspan(key_length + 1);
1898 if (
keys.size() < 1 ||
keys.size() > max_keys)
return false;
1905 script_size += 2 + (
keys.size() > 16) + (
k > 16) + 34 *
keys.size();
1911 while (!to_parse.empty()) {
1912 if (script_size > max_size)
return {};
1915 auto [cur_context, n,
k] = to_parse.back();
1916 to_parse.pop_back();
1918 switch (cur_context) {
1920 std::optional<size_t> colon_index{};
1921 for (
size_t i = 1; i < in.size(); ++i) {
1926 if (in[i] <
'a' || in[i] >
'z')
break;
1929 bool last_was_v{
false};
1930 for (
size_t j = 0; colon_index && j < *colon_index; ++j) {
1931 if (script_size > max_size)
return {};
1935 }
else if (in[j] ==
's') {
1938 }
else if (in[j] ==
'c') {
1941 }
else if (in[j] ==
'd') {
1944 }
else if (in[j] ==
'j') {
1947 }
else if (in[j] ==
'n') {
1950 }
else if (in[j] ==
'v') {
1953 if (last_was_v)
return {};
1955 }
else if (in[j] ==
'u') {
1958 }
else if (in[j] ==
't') {
1961 }
else if (in[j] ==
'l') {
1969 last_was_v = (in[j] ==
'v');
1972 if (colon_index) in = in.subspan(*colon_index + 1);
1976 if (
Const(
"0", in)) {
1978 }
else if (
Const(
"1", in)) {
1980 }
else if (
Const(
"pk(", in,
false)) {
1982 if (!key)
return {};
1984 script_size +=
IsTapscript(ctx.MsContext()) ? 33 : 34;
1985 }
else if (
Const(
"pkh(", in,
false)) {
1987 if (!key)
return {};
1990 }
else if (
Const(
"pk_k(", in,
false)) {
1992 if (!key)
return {};
1994 script_size +=
IsTapscript(ctx.MsContext()) ? 32 : 33;
1995 }
else if (
Const(
"pk_h(", in,
false)) {
1997 if (!key)
return {};
2000 }
else if (
Const(
"sha256(", in,
false)) {
2001 std::optional<std::vector<unsigned char>> hash =
ParseHexStr(
"sha256", in, 32, ctx);
2002 if (!hash)
return {};
2005 }
else if (
Const(
"ripemd160(", in,
false)) {
2006 std::optional<std::vector<unsigned char>> hash =
ParseHexStr(
"ripemd160", in, 20, ctx);
2007 if (!hash)
return {};
2010 }
else if (
Const(
"hash256(", in,
false)) {
2011 std::optional<std::vector<unsigned char>> hash =
ParseHexStr(
"hash256", in, 32, ctx);
2012 if (!hash)
return {};
2015 }
else if (
Const(
"hash160(", in,
false)) {
2016 std::optional<std::vector<unsigned char>> hash =
ParseHexStr(
"hash160", in, 20, ctx);
2017 if (!hash)
return {};
2020 }
else if (
Const(
"after(", in,
false)) {
2021 auto expr =
Expr(in);
2022 if (!
Func(
"after", expr))
return {};
2024 if (!num.has_value() || *num < 1 || *num >= 0x80000000L)
return {};
2026 script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
2027 }
else if (
Const(
"older(", in,
false)) {
2028 auto expr =
Expr(in);
2029 if (!
Func(
"older", expr))
return {};
2031 if (!num.has_value() || *num < 1 || *num >= 0x80000000L)
return {};
2033 script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff);
2034 }
else if (
Const(
"multi(", in)) {
2035 if (!parse_multi_exp(in,
false))
return {};
2036 }
else if (
Const(
"multi_a(", in)) {
2037 if (!parse_multi_exp(in,
true))
return {};
2038 }
else if (
Const(
"thresh(", in)) {
2040 if (next_comma < 1)
return {};
2042 if (!
k.has_value() || *
k < 1)
return {};
2043 in = in.subspan(next_comma + 1);
2047 script_size += 2 + (*
k > 16) + (*
k > 0x7f) + (*
k > 0x7fff) + (*
k > 0x7fffff);
2048 }
else if (
Const(
"andor(", in)) {
2058 if (
Const(
"and_n(", in)) {
2061 }
else if (
Const(
"and_b(", in)) {
2064 }
else if (
Const(
"and_v(", in)) {
2067 }
else if (
Const(
"or_b(", in)) {
2070 }
else if (
Const(
"or_c(", in)) {
2073 }
else if (
Const(
"or_d(", in)) {
2076 }
else if (
Const(
"or_i(", in)) {
2114 script_size += (constructed.back().
GetType() <<
"x"_mst);
2131 auto mid = std::move(constructed.back());
2132 constructed.pop_back();
2136 case ParseContext::AND_V: {
2140 case ParseContext::OR_B: {
2144 case ParseContext::OR_C: {
2148 case ParseContext::OR_D: {
2152 case ParseContext::OR_I: {
2156 case ParseContext::ANDOR: {
2157 auto right = std::move(constructed.back());
2158 constructed.pop_back();
2159 auto mid = std::move(constructed.back());
2160 constructed.pop_back();
2161 constructed.back() =
Node{internal::NoDupCheck{}, ctx.MsContext(),
Fragment::ANDOR,
Vector(std::move(constructed.back()), std::move(mid), std::move(right))};
2164 case ParseContext::THRESH: {
2165 if (in.size() < 1)
return {};
2168 to_parse.emplace_back(ParseContext::THRESH, n+1,
k);
2169 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
2171 }
else if (in[0] ==
')') {
2172 if (
k > n)
return {};
2175 std::vector<Node<Key>>
subs;
2176 for (
int i = 0; i < n; ++i) {
2177 subs.push_back(std::move(constructed.back()));
2178 constructed.pop_back();
2180 std::reverse(
subs.begin(),
subs.end());
2181 constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(),
Fragment::THRESH, std::move(
subs),
k);
2187 case ParseContext::COMMA: {
2188 if (in.size() < 1 || in[0] !=
',')
return {};
2192 case ParseContext::CLOSE_BRACKET: {
2193 if (in.size() < 1 || in[0] !=
')')
return {};
2201 assert(constructed.size() >= 1);
2203 assert(constructed[0].ScriptSize() == script_size);
2204 if (in.size() > 0)
return {};
2205 Node<Key> tl_node{std::move(constructed.front())};
2206 tl_node.DuplicateKeyCheck(ctx);
2292template <
typename Key,
typename Ctx,
typename I>
2296 std::vector<std::tuple<DecodeContext, int64_t, int64_t>> to_parse;
2297 std::vector<Node<Key>> constructed;
2303 while (!to_parse.empty()) {
2305 if (!constructed.empty() && !constructed.back().IsValid())
return {};
2308 auto [cur_context, n,
k] = to_parse.back();
2309 to_parse.pop_back();
2311 switch(cur_context) {
2313 if (in >= last)
return {};
2316 if (in[0].first ==
OP_1) {
2321 if (in[0].first ==
OP_0) {
2327 if (in[0].second.size() == 33 || in[0].second.size() == 32) {
2328 auto key = ctx.FromPKBytes(in[0].second.begin(), in[0].second.end());
2329 if (!key)
return {};
2335 auto key = ctx.FromPKHBytes(in[2].second.begin(), in[2].second.end());
2336 if (!key)
return {};
2342 std::optional<int64_t> num;
2345 if (*num < 1 || *num > 0x7FFFFFFFL)
return {};
2351 if (num < 1 || num > 0x7FFFFFFFL)
return {};
2357 if (in[2].first ==
OP_SHA256 && in[1].second.size() == 32) {
2361 }
else if (in[2].first ==
OP_RIPEMD160 && in[1].second.size() == 20) {
2365 }
else if (in[2].first ==
OP_HASH256 && in[1].second.size() == 32) {
2369 }
else if (in[2].first ==
OP_HASH160 && in[1].second.size() == 20) {
2378 std::vector<Key> keys;
2380 if (!n || last - in < 3 + *n)
return {};
2381 if (*n < 1 || *n > 20)
return {};
2382 for (
int i = 0; i < *n; ++i) {
2383 if (in[2 + i].second.size() != 33)
return {};
2384 auto key = ctx.FromPKBytes(in[2 + i].second.begin(), in[2 + i].second.end());
2385 if (!key)
return {};
2386 keys.push_back(std::move(*key));
2391 std::reverse(keys.begin(), keys.end());
2396 if (last - in >= 4 && in[0].first ==
OP_NUMEQUAL) {
2402 if (last - in < 2 + *
k * 2)
return {};
2403 std::vector<Key> keys;
2406 for (
int pos = 2;; pos += 2) {
2407 if (last - in < pos + 2)
return {};
2410 if (in[pos + 1].second.size() != 32)
return {};
2411 auto key = ctx.FromPKBytes(in[pos + 1].second.begin(), in[pos + 1].second.end());
2412 if (!key)
return {};
2413 keys.push_back(std::move(*key));
2419 if (keys.size() < (
size_t)*
k)
return {};
2420 in += 2 + keys.size() * 2;
2421 std::reverse(keys.begin(), keys.end());
2451 if (*num < 1)
return {};
2494 if (in >= last)
return {};
2515 if (in >= last || in[0].first !=
OP_SWAP || constructed.empty())
return {};
2521 if (in >= last || in[0].first !=
OP_TOALTSTACK || constructed.empty())
return {};
2527 if (constructed.empty())
return {};
2532 if (constructed.empty())
return {};
2537 if (constructed.empty())
return {};
2542 if (constructed.empty())
return {};
2547 if (constructed.empty())
return {};
2552 if (constructed.size() < 2)
return {};
2557 if (constructed.size() < 2)
return {};
2562 if (constructed.size() < 2)
return {};
2567 if (constructed.size() < 2)
return {};
2572 if (constructed.size() < 2)
return {};
2577 if (constructed.size() < 3)
return {};
2578 Node left{std::move(constructed.back())};
2579 constructed.pop_back();
2580 Node right{std::move(constructed.back())};
2581 constructed.pop_back();
2582 Node mid{std::move(constructed.back())};
2587 if (in >= last)
return {};
2588 if (in[0].first ==
OP_ADD) {
2600 if (
k < 1 || k > n || constructed.size() <
static_cast<size_t>(n))
return {};
2601 std::vector<Node<Key>> subs;
2602 for (
int i = 0; i < n; ++i) {
2603 Node sub{std::move(constructed.back())};
2604 constructed.pop_back();
2605 subs.push_back(std::move(sub));
2611 if (in >= last)
return {};
2620 else if (in[0].first ==
OP_IF) {
2621 if (last - in >= 2 && in[1].first ==
OP_DUP) {
2632 }
else if (in[0].first ==
OP_NOTIF) {
2642 if (in >= last)
return {};
2654 if (in >= last)
return {};
2655 if (in[0].first ==
OP_IF) {
2658 }
else if (in[0].first ==
OP_NOTIF) {
2670 if (constructed.size() != 1)
return {};
2671 Node tl_node{std::move(constructed.front())};
2681template <
typename Ctx>
2682inline std::optional<Node<typename Ctx::Key>>
FromString(
const std::string& str,
const Ctx& ctx)
2687template <
typename Ctx>
2692 if (
script.size() > MaxScriptSize(ctx.MsContext()))
return {};
2693 auto decomposed = DecomposeScript(
script);
2694 if (!decomposed)
return {};
2695 auto it = decomposed->begin();
2696 auto ret = DecodeScript<typename Ctx::Key>(it, decomposed->end(), ctx);
2697 if (!
ret)
return {};
2698 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
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
Node(internal::NoDupCheck, MiniscriptContext script_ctx, enum Fragment nt, std::vector< unsigned char > arg, uint32_t val=0)
bool IsSatisfiable(F fn) const
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 UniValue Parse(std::string_view raw, ParamFormat format=ParamFormat::JSON)
Parse string to UniValue or throw runtime_error if string contains invalid JSON.
static const int WITNESS_SCALE_FACTOR
uint160 RIPEMD160(std::span< const unsigned char > data)
Compute the 160-bit RIPEMD-160 hash of an array.
std::string HexStr(const std::span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
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)
@ OR_I
OR_I will construct an or_i node from the last two constructed nodes.
@ VERIFY
VERIFY wraps the top constructed node with v:
@ OR_B
OR_B will construct an or_b node from the last two constructed nodes.
@ 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:
@ ANDOR
ANDOR will construct an andor node from the last three constructed nodes.
@ THRESH
THRESH will read a wrapped expression, and then look for a COMMA.
@ COMMA
COMMA expects the next element to be ',' and fails if not.
@ AND_V
AND_V will construct an and_v node from the last two constructed nodes.
@ CHECK
CHECK wraps the top constructed node with c:
@ DUP_IF
DUP_IF wraps the top constructed node with d:
@ OR_C
OR_C will construct an or_c node from the last two constructed nodes.
@ 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.
@ OR_D
OR_D will construct an or_d node from the last two constructed nodes.
@ AND_B
AND_B will construct an and_b node from the last two constructed nodes.
@ 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.
@ VERIFY
VERIFY wraps the top constructed node with v:
@ SINGLE_BKV_EXPR
A single expression of type B, K, or V.
@ OR_B
OR_B will construct an or_b node from the last two constructed nodes.
@ 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,...
@ SWAP
SWAP expects the next element to be OP_SWAP (inside a W-type expression that didn't end with FROMALTS...
@ ANDOR
ANDOR will construct an andor node from the last three constructed nodes.
@ W_EXPR
An expression of type W (a: or s: wrappers).
@ AND_V
AND_V will construct an and_v node from the last two constructed nodes.
@ THRESH_E
THRESH_E constructs a thresh node from the appropriate number of constructed children.
@ CHECK
CHECK wraps the top constructed node with c:
@ DUP_IF
DUP_IF wraps the top constructed node with d:
@ OR_C
OR_C will construct an or_c node from the last two constructed nodes.
@ ENDIF
ENDIF signals that we are inside some sort of OP_IF structure, which could be or_d,...
@ ZERO_NOTEQUAL
ZERO_NOTEQUAL wraps the top constructed node with n:
@ NON_ZERO
NON_ZERO wraps the top constructed node with j:
@ OR_D
OR_D will construct an or_d node from the last two constructed nodes.
@ AND_B
AND_B will construct an and_b node from the last two constructed nodes.
@ ALT
ALT expects the next element to be TOALTSTACK (we must have already read a FROMALTSTACK earlier),...
@ 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...
std::pair< opcodetype, std::vector< unsigned char > > Opcode
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)
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.
std::optional< T > ToIntegral(std::string_view str, size_t base=10)
Convert string to integral type T.
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.