5 #ifndef BITCOIN_SCRIPT_MINISCRIPT_H 6 #define BITCOIN_SCRIPT_MINISCRIPT_H 130 friend constexpr
Type operator"" _mst(
const char* c,
size_t l);
152 inline constexpr
Type operator"" _mst(
const char* c,
size_t l) {
155 for (
const char *p = c; p < c + l; p++) {
167 *p ==
'f' ? 1 << 10 :
168 *p ==
's' ? 1 << 11 :
169 *p ==
'm' ? 1 << 12 :
170 *p ==
'x' ? 1 << 13 :
171 *p ==
'g' ? 1 << 14 :
172 *p ==
'h' ? 1 << 15 :
173 *p ==
'i' ? 1 << 16 :
174 *p ==
'j' ? 1 << 17 :
175 *p ==
'k' ? 1 << 18 :
176 (
throw std::logic_error(
"Unknown character in _mst literal"), 0)
183 using Opcode = std::pair<opcodetype, std::vector<unsigned char>>;
185 template<
typename Key>
struct Node;
186 template<
typename Key>
using NodeRef = std::shared_ptr<const Node<Key>>;
189 template<
typename Key,
typename... Args>
230 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);
253 if (!a.
valid)
return b;
254 if (!b.
valid)
return a;
284 template<
typename Key>
289 const uint32_t
k = 0;
293 const std::vector<unsigned char>
data;
295 const std::vector<NodeRef<Key>>
subs;
317 for (
const auto& sub :
subs) {
318 subsize += sub->ScriptSize();
320 Type sub0type =
subs.size() > 0 ?
subs[0]->GetType() :
""_mst;
347 template<
typename Result,
typename State,
typename DownFn,
typename UpFn>
357 StackElem(
const Node& node_,
size_t exp_,
State&& state_) :
358 node(node_), expanded(exp_), state(std::move(state_)) {}
361 std::vector<StackElem> stack;
364 std::vector<Result> results;
365 stack.emplace_back(*
this, 0, std::move(root_state));
383 while (stack.size()) {
384 const Node&
node = stack.back().node;
385 if (stack.back().expanded <
node.subs.size()) {
389 size_t child_index = stack.back().expanded++;
390 State child_state = downfn(stack.back().state,
node, child_index);
391 stack.emplace_back(*
node.subs[child_index], 0, std::move(child_state));
396 std::optional<Result> result{upfn(std::move(stack.back().state),
node,
399 if (!result)
return {};
401 results.erase(results.end() -
node.subs.size(), results.end());
402 results.push_back(std::move(*result));
406 assert(results.size() == 1);
407 return std::move(results[0]);
412 template<
typename Result,
typename UpFn>
415 struct DummyState {};
416 return TreeEvalMaybe<Result>(DummyState{},
417 [](DummyState,
const Node&, size_t) {
return DummyState{}; },
425 template<
typename Result,
typename State,
typename DownFn,
typename UpFn>
430 return std::move(*TreeEvalMaybe<Result>(std::move(root_state),
431 std::forward<DownFn>(downfn),
434 return std::optional<Result>(std::move(res));
441 template<
typename Result,
typename UpFn>
444 struct DummyState {};
445 return std::move(*TreeEvalMaybe<Result>(DummyState{},
446 [](DummyState,
const Node&, size_t) {
return DummyState{}; },
449 return std::optional<Result>(std::move(res));
457 std::vector<std::pair<const Node<Key>&,
const Node<Key>&>> queue;
458 queue.emplace_back(node1, node2);
459 while (!queue.empty()) {
460 const auto& [a, b] = queue.back();
462 if (std::tie(a.fragment, a.k, a.keys, a.data) < std::tie(b.fragment, b.k, b.keys, b.data))
return -1;
463 if (std::tie(b.fragment, b.k, b.keys, b.data) < std::tie(a.fragment, a.k, a.keys, a.data))
return 1;
464 if (a.subs.size() < b.subs.size())
return -1;
465 if (b.subs.size() < a.subs.size())
return 1;
466 size_t n = a.
subs.size();
467 for (
size_t i = 0; i < n; ++i) {
468 queue.emplace_back(*a.subs[n - 1 - i], *b.subs[n - 1 - i]);
476 using namespace internal;
479 std::vector<Type> sub_types;
481 for (
const auto& sub :
subs) sub_types.push_back(sub->GetType());
492 template<
typename Ctx>
510 switch (
node.fragment) {
524 if (
node.subs[0]->GetType() <<
"x"_mst) {
527 return std::move(
subs[0]);
543 for (
const auto& key :
node.keys) {
550 for (
size_t i = 1; i <
subs.size(); ++i) {
558 return TreeEval<CScript>(
false, downfn, upfn);
561 template<
typename CTx>
566 auto downfn = [](bool,
const Node&
node, size_t) {
578 std::string
ret = wrapped ?
":" :
"";
580 switch (
node.fragment) {
586 auto key_str =
ctx.ToString(
node.subs[0]->keys[0]);
587 if (!key_str)
return {};
588 return std::move(
ret) +
"pk(" + std::move(*key_str) +
")";
592 auto key_str =
ctx.ToString(
node.subs[0]->keys[0]);
593 if (!key_str)
return {};
594 return std::move(
ret) +
"pkh(" + std::move(*key_str) +
")";
596 return "c" + std::move(
subs[0]);
611 switch (
node.fragment) {
613 auto key_str =
ctx.ToString(
node.keys[0]);
614 if (!key_str)
return {};
615 return std::move(
ret) +
"pk_k(" + std::move(*key_str) +
")";
618 auto key_str =
ctx.ToString(
node.keys[0]);
619 if (!key_str)
return {};
620 return std::move(
ret) +
"pk_h(" + std::move(*key_str) +
")";
639 return std::move(
ret) +
"andor(" + std::move(
subs[0]) +
"," + std::move(
subs[1]) +
"," + std::move(
subs[2]) +
")";
642 for (
const auto& key :
node.keys) {
643 auto key_str =
ctx.ToString(key);
644 if (!key_str)
return {};
645 str +=
"," + std::move(*key_str);
647 return std::move(str) +
")";
651 for (
auto& sub :
subs) {
652 str +=
"," + std::move(sub);
654 return std::move(str) +
")";
661 return TreeEvalMaybe<std::string>(
false, downfn, upfn);
679 const auto count{1 +
subs[0]->ops.count +
subs[1]->ops.count};
680 const auto sat{
subs[0]->ops.sat +
subs[1]->ops.sat};
681 const auto dsat{
subs[0]->ops.dsat +
subs[1]->ops.dsat};
682 return {
count, sat, dsat};
685 const auto count{1 +
subs[0]->ops.count +
subs[1]->ops.count};
687 const auto dsat{
subs[0]->ops.dsat +
subs[1]->ops.dsat};
688 return {
count, sat, dsat};
691 const auto count{3 +
subs[0]->ops.count +
subs[1]->ops.count};
692 const auto sat{
subs[0]->ops.sat | (
subs[1]->ops.sat +
subs[0]->ops.dsat)};
693 const auto dsat{
subs[0]->ops.dsat +
subs[1]->ops.dsat};
694 return {
count, sat, dsat};
697 const auto count{2 +
subs[0]->ops.count +
subs[1]->ops.count};
698 const auto sat{
subs[0]->ops.sat | (
subs[1]->ops.sat +
subs[0]->ops.dsat)};
699 return {
count, sat, {}};
702 const auto count{3 +
subs[0]->ops.count +
subs[1]->ops.count};
703 const auto sat{
subs[0]->ops.sat |
subs[1]->ops.sat};
704 const auto dsat{
subs[0]->ops.dsat |
subs[1]->ops.dsat};
705 return {
count, sat, dsat};
708 const auto count{3 +
subs[0]->ops.count +
subs[1]->ops.count +
subs[2]->ops.count};
710 const auto dsat{
subs[0]->ops.dsat +
subs[2]->ops.dsat};
711 return {
count, sat, dsat};
724 for (
const auto& sub :
subs) {
725 count += sub->ops.count + 1;
726 auto next_sats =
Vector(sats[0] + sub->ops.dsat);
727 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub->ops.dsat) | (sats[j - 1] + sub->ops.sat));
728 next_sats.push_back(sats[sats.size() - 1] + sub->ops.sat);
729 sats = std::move(next_sats);
732 return {
count, sats[
k], sats[0]};
752 const auto dsat{
subs[0]->ss.dsat +
subs[2]->ss.dsat};
759 const auto dsat{
subs[0]->ss.dsat +
subs[1]->ss.dsat};
775 for (
const auto& sub :
subs) {
776 auto next_sats =
Vector(sats[0] + sub->ss.dsat);
777 for (
size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + sub->ss.dsat) | (sats[j - 1] + sub->ss.sat));
778 next_sats.push_back(sats[sats.size() - 1] + sub->ss.sat);
779 sats = std::move(next_sats);
782 return {sats[
k], sats[0]};
800 Comp(
const Ctx&
ctx) : ctx_ptr(&
ctx) {}
801 bool operator()(
const Key& a,
const Key& b)
const {
return ctx_ptr->KeyCompare(a, b); }
807 using keyset = std::set<Key, Comp>;
808 using state = std::optional<keyset>;
812 if (
node.has_duplicate_keys.has_value() && *
node.has_duplicate_keys)
return {};
815 for (
auto& sub :
subs) {
816 if (!sub.has_value()) {
817 node.has_duplicate_keys =
true;
824 size_t keys_count =
node.keys.size();
825 keyset key_set{
node.keys.begin(),
node.keys.end(), Comp(
ctx)};
826 if (key_set.size() != keys_count) {
828 node.has_duplicate_keys =
true;
833 for (
auto& sub :
subs) {
834 keys_count += sub->size();
837 if (key_set.size() < sub->size()) std::swap(key_set, *sub);
839 if (key_set.size() != keys_count) {
840 node.has_duplicate_keys =
true;
845 node.has_duplicate_keys =
false;
849 TreeEval<state>(upfn);
874 for (
auto& sub:
subs)
if (sub)
return sub;
875 if (!
node.IsSaneSubexpression())
return &
node;
911 Node(
internal::NoDupCheck,
Fragment nt, std::vector<
NodeRef<Key>> sub, std::vector<unsigned char> arg, uint32_t val = 0) :
fragment(nt),
k(val),
data(
std::move(arg)),
subs(
std::move(sub)),
ops(
CalcOps()),
ss(
CalcStackSize()),
typ(
CalcType()),
scriptlen(
CalcScriptLen()) {}
913 Node(
internal::NoDupCheck,
Fragment nt, std::vector<
NodeRef<Key>> sub, std::vector<Key> key, uint32_t val = 0) :
fragment(nt),
k(val),
keys(
std::move(key)),
subs(
std::move(sub)),
ops(
CalcOps()),
ss(
CalcStackSize()),
typ(
CalcType()),
scriptlen(
CalcScriptLen()) {}
986 template<
typename Key,
typename Ctx>
990 if (key_size < 1)
return {};
991 auto key =
ctx.FromString(in.
begin(), in.
begin() + key_size);
993 return {{std::move(*key), key_size}};
997 template<
typename Ctx>
1002 if (hash_size < 1)
return {};
1003 std::string val = std::string(in.
begin(), in.
begin() + hash_size);
1004 if (!
IsHex(val))
return {};
1006 if (hash.size() != expected_size)
return {};
1007 return {{std::move(hash), hash_size}};
1011 template<
typename Key>
1015 constructed.pop_back();
1028 template<
typename Key,
typename Ctx>
1043 size_t script_size{1};
1046 std::vector<std::tuple<ParseContext, int64_t, int64_t>> to_parse;
1047 std::vector<NodeRef<Key>> constructed;
1051 while (!to_parse.empty()) {
1055 auto [cur_context, n,
k] = to_parse.back();
1056 to_parse.pop_back();
1058 switch (cur_context) {
1060 std::optional<size_t> colon_index{};
1061 for (
size_t i = 1; i < in.
size(); ++i) {
1066 if (in[i] <
'a' || in[i] >
'z')
break;
1069 bool last_was_v{
false};
1070 for (
size_t j = 0; colon_index && j < *colon_index; ++j) {
1075 }
else if (in[j] ==
's') {
1078 }
else if (in[j] ==
'c') {
1081 }
else if (in[j] ==
'd') {
1084 }
else if (in[j] ==
'j') {
1087 }
else if (in[j] ==
'n') {
1090 }
else if (in[j] ==
'v') {
1093 if (last_was_v)
return {};
1095 }
else if (in[j] ==
'u') {
1098 }
else if (in[j] ==
't') {
1101 }
else if (in[j] ==
'l') {
1109 last_was_v = (in[j] ==
'v');
1112 if (colon_index) in = in.
subspan(*colon_index + 1);
1116 if (
Const(
"0", in)) {
1118 }
else if (
Const(
"1", in)) {
1120 }
else if (
Const(
"pk(", in)) {
1121 auto res = ParseKeyEnd<Key, Ctx>(in,
ctx);
1122 if (!res)
return {};
1123 auto& [key, key_size] = *res;
1125 in = in.subspan(key_size + 1);
1127 }
else if (
Const(
"pkh(", in)) {
1128 auto res = ParseKeyEnd<Key>(in,
ctx);
1129 if (!res)
return {};
1130 auto& [key, key_size] = *res;
1132 in = in.subspan(key_size + 1);
1134 }
else if (
Const(
"pk_k(", in)) {
1135 auto res = ParseKeyEnd<Key>(in,
ctx);
1136 if (!res)
return {};
1137 auto& [key, key_size] = *res;
1139 in = in.subspan(key_size + 1);
1141 }
else if (
Const(
"pk_h(", in)) {
1142 auto res = ParseKeyEnd<Key>(in,
ctx);
1143 if (!res)
return {};
1144 auto& [key, key_size] = *res;
1146 in = in.subspan(key_size + 1);
1148 }
else if (
Const(
"sha256(", in)) {
1150 if (!res)
return {};
1151 auto& [hash, hash_size] = *res;
1153 in = in.
subspan(hash_size + 1);
1155 }
else if (
Const(
"ripemd160(", in)) {
1157 if (!res)
return {};
1158 auto& [hash, hash_size] = *res;
1160 in = in.
subspan(hash_size + 1);
1162 }
else if (
Const(
"hash256(", in)) {
1164 if (!res)
return {};
1165 auto& [hash, hash_size] = *res;
1167 in = in.
subspan(hash_size + 1);
1169 }
else if (
Const(
"hash160(", in)) {
1171 if (!res)
return {};
1172 auto& [hash, hash_size] = *res;
1174 in = in.
subspan(hash_size + 1);
1176 }
else if (
Const(
"after(", in)) {
1178 if (arg_size < 1)
return {};
1181 if (num < 1 || num >= 0x80000000L)
return {};
1183 in = in.
subspan(arg_size + 1);
1184 script_size += 1 + (num > 16) + (num > 0x7f) + (num > 0x7fff) + (num > 0x7fffff);
1185 }
else if (
Const(
"older(", in)) {
1187 if (arg_size < 1)
return {};
1190 if (num < 1 || num >= 0x80000000L)
return {};
1192 in = in.
subspan(arg_size + 1);
1193 script_size += 1 + (num > 16) + (num > 0x7f) + (num > 0x7fff) + (num > 0x7fffff);
1194 }
else if (
Const(
"multi(", in)) {
1197 if (next_comma < 1)
return {};
1199 in = in.
subspan(next_comma + 1);
1201 std::vector<Key> keys;
1202 while (next_comma != -1) {
1204 int key_length = (next_comma == -1) ?
FindNextChar(in,
')') : next_comma;
1205 if (key_length < 1)
return {};
1206 auto key =
ctx.FromString(in.
begin(), in.
begin() + key_length);
1207 if (!key)
return {};
1208 keys.push_back(std::move(*key));
1209 in = in.
subspan(key_length + 1);
1211 if (keys.size() < 1 || keys.size() > 20)
return {};
1212 if (k < 1 || k > (int64_t)keys.size())
return {};
1213 script_size += 2 + (keys.size() > 16) + (
k > 16) + 34 * keys.size();
1215 }
else if (
Const(
"thresh(", in)) {
1217 if (next_comma < 1)
return {};
1219 if (
k < 1)
return {};
1220 in = in.
subspan(next_comma + 1);
1224 script_size += 2 + (
k > 16) + (
k > 0x7f) + (
k > 0x7fff) + (
k > 0x7fffff);
1225 }
else if (
Const(
"andor(", in)) {
1235 if (
Const(
"and_n(", in)) {
1238 }
else if (
Const(
"and_b(", in)) {
1241 }
else if (
Const(
"and_v(", in)) {
1244 }
else if (
Const(
"or_b(", in)) {
1247 }
else if (
Const(
"or_c(", in)) {
1250 }
else if (
Const(
"or_d(", in)) {
1253 }
else if (
Const(
"or_i(", in)) {
1291 script_size += (constructed.back()->GetType() <<
"x"_mst);
1308 auto mid = std::move(constructed.back());
1309 constructed.pop_back();
1334 auto right = std::move(constructed.back());
1335 constructed.pop_back();
1336 auto mid = std::move(constructed.back());
1337 constructed.pop_back();
1342 if (in.
size() < 1)
return {};
1348 }
else if (in[0] ==
')') {
1349 if (
k > n)
return {};
1352 std::vector<NodeRef<Key>> subs;
1353 for (
int i = 0; i < n; ++i) {
1354 subs.push_back(std::move(constructed.back()));
1355 constructed.pop_back();
1357 std::reverse(subs.begin(), subs.end());
1365 if (in.
size() < 1 || in[0] !=
',')
return {};
1370 if (in.
size() < 1 || in[0] !=
')')
return {};
1378 assert(constructed.size() == 1);
1379 assert(constructed[0]->ScriptSize() == script_size);
1380 if (in.
size() > 0)
return {};
1381 const NodeRef<Key> tl_node = std::move(constructed.front());
1382 tl_node->DuplicateKeyCheck(
ctx);
1468 template<
typename Key,
typename Ctx,
typename I>
1472 std::vector<std::tuple<DecodeContext, int64_t, int64_t>> to_parse;
1473 std::vector<NodeRef<Key>> constructed;
1479 while (!to_parse.empty()) {
1481 if (!constructed.empty() && !constructed.back()->IsValid())
return {};
1484 auto [cur_context, n,
k] = to_parse.back();
1485 to_parse.pop_back();
1487 switch(cur_context) {
1489 if (in >= last)
return {};
1492 if (in[0].first ==
OP_1) {
1497 if (in[0].first ==
OP_0) {
1503 if (in[0].second.size() == 33) {
1504 auto key =
ctx.FromPKBytes(in[0].second.begin(), in[0].second.end());
1505 if (!key)
return {};
1511 auto key =
ctx.FromPKHBytes(in[2].second.begin(), in[2].second.end());
1512 if (!key)
return {};
1518 std::optional<int64_t> num;
1521 if (*num < 1 || *num > 0x7FFFFFFFL)
return {};
1527 if (num < 1 || num > 0x7FFFFFFFL)
return {};
1533 if (in[2].first ==
OP_SHA256 && in[1].second.size() == 32) {
1537 }
else if (in[2].first ==
OP_RIPEMD160 && in[1].second.size() == 20) {
1541 }
else if (in[2].first ==
OP_HASH256 && in[1].second.size() == 32) {
1545 }
else if (in[2].first ==
OP_HASH160 && in[1].second.size() == 20) {
1553 std::vector<Key> keys;
1555 if (!n || last - in < 3 + *n)
return {};
1556 if (*n < 1 || *n > 20)
return {};
1557 for (
int i = 0; i < *n; ++i) {
1558 if (in[2 + i].second.size() != 33)
return {};
1559 auto key =
ctx.FromPKBytes(in[2 + i].second.begin(), in[2 + i].second.end());
1560 if (!key)
return {};
1561 keys.push_back(std::move(*key));
1564 if (!
k || *k < 1 || *k > *n)
return {};
1566 std::reverse(keys.begin(), keys.end());
1596 if (*num < 1)
return {};
1639 if (in >= last)
return {};
1660 if (in >= last || in[0].first !=
OP_SWAP || constructed.empty())
return {};
1666 if (in >= last || in[0].first !=
OP_TOALTSTACK || constructed.empty())
return {};
1672 if (constructed.empty())
return {};
1677 if (constructed.empty())
return {};
1682 if (constructed.empty())
return {};
1687 if (constructed.empty())
return {};
1692 if (constructed.empty())
return {};
1697 if (constructed.size() < 2)
return {};
1702 if (constructed.size() < 2)
return {};
1707 if (constructed.size() < 2)
return {};
1712 if (constructed.size() < 2)
return {};
1717 if (constructed.size() < 2)
return {};
1722 if (constructed.size() < 3)
return {};
1724 constructed.pop_back();
1726 constructed.pop_back();
1732 if (in >= last)
return {};
1733 if (in[0].first ==
OP_ADD) {
1745 if (k < 1 || k > n || constructed.size() <
static_cast<size_t>(n))
return {};
1746 std::vector<NodeRef<Key>> subs;
1747 for (
int i = 0; i < n; ++i) {
1749 constructed.pop_back();
1750 subs.push_back(std::move(sub));
1756 if (in >= last)
return {};
1765 else if (in[0].first ==
OP_IF) {
1766 if (last - in >= 2 && in[1].first ==
OP_DUP) {
1777 }
else if (in[0].first ==
OP_NOTIF) {
1787 if (in >= last)
return {};
1799 if (in >= last)
return {};
1800 if (in[0].first ==
OP_IF) {
1803 }
else if (in[0].first ==
OP_NOTIF) {
1815 if (constructed.size() != 1)
return {};
1816 const NodeRef<Key> tl_node = std::move(constructed.front());
1817 tl_node->DuplicateKeyCheck(
ctx);
1820 if (!tl_node->IsValidTopLevel())
return {};
1826 template<
typename Ctx>
1828 return internal::Parse<typename Ctx::Key>(str,
ctx);
1831 template<
typename Ctx>
1833 using namespace internal;
1837 if (!decomposed)
return {};
1838 auto it = decomposed->begin();
1839 auto ret = DecodeScript<typename Ctx::Key>(it, decomposed->end(),
ctx);
1840 if (!
ret)
return {};
1841 if (it != decomposed->end())
return {};
1847 #endif // BITCOIN_SCRIPT_MINISCRIPT_H CScript BuildScript(Ts &&... inputs)
Build a script by concatenating other scripts, or any argument accepted by CScript::operator<<.
OP_SIZE 32 OP_EQUALVERIFY OP_HASH160 [hash] OP_EQUAL.
NodeRef< typename Ctx::Key > FromString(const std::string &str, const Ctx &ctx)
A node in a miniscript expression.
CONSTEXPR_IF_NOT_DEBUG Span< C > subspan(std::size_t offset) const noexcept
Potentially multiple SINGLE_BKV_EXPRs as children of (potentially multiple) and_v expressions...
[X] OP_VERIFY (or -VERIFY version of last opcode in X)
SWAP wraps the top constructed node with s:
MaxInt< uint32_t > sat
Maximum stack size to satisfy;.
friend MaxInt< I > operator+(const MaxInt< I > &a, const MaxInt< I > &b)
[X] OP_NOTIF [Z] OP_ELSE [Y] OP_ENDIF
Node(const Ctx &ctx, Fragment nt, std::vector< unsigned char > arg, uint32_t val=0)
CHECK wraps the top constructed node with c:
std::optional< std::pair< Key, int > > ParseKeyEnd(Span< const char > in, const Ctx &ctx)
Parse a key 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)
Helper function for Node::CalcType.
OP_DUP OP_HASH160 [keyhash] OP_EQUALVERIFY.
ALT wraps the top constructed node with a:
const std::vector< unsigned char > data
The data bytes in this expression (only for HASH160/HASH256/SHA256/RIPEMD10).
VERIFY wraps the top constructed node with v:
OP_SIZE 32 OP_EQUALVERIFY OP_RIPEMD160 [hash] OP_EQUAL.
const Node * FindInsaneSub() const
Find an insane subnode which has no insane children. Nullptr if there is none.
std::optional< Result > TreeEvalMaybe(UpFn upfn) const
Like TreeEvalMaybe, but without downfn or State type.
[k] [key_n]* [n] OP_CHECKMULTISIG
std::optional< Result > TreeEvalMaybe(State root_state, DownFn downfn, UpFn upfn) const
MaxInt< uint32_t > dsat
Maximum stack size to dissatisfy;.
[n] OP_CHECKLOCKTIMEVERIFY
bool CheckDuplicateKey() const
Check whether there is no duplicate key across this fragment and all its sub-fragments.
bool Const(const std::string &str, Span< const char > &sp)
Parse a constant.
OP_TOALTSTACK [X] OP_FROMALTSTACK.
const uint32_t k
The k parameter (time for OLDER/AFTER, threshold for THRESH(_M))
bool IsHex(std::string_view str)
bool IsValid() const
Check whether this node is valid at all.
constexpr std::size_t size() const noexcept
If, inside an ENDIF context, we find an OP_NOTIF before finding an OP_ELSE, we could either be in an ...
std::optional< std::pair< std::vector< unsigned char >, int > > ParseHexStrEnd(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.
uint32_t GetStackSize() const
Return the maximum number of stack elements needed to satisfy this script non-malleably, including the script push.
Type CalcType() const
Compute the type for this miniscript.
Node(const Ctx &ctx, Fragment nt, std::vector< NodeRef< Key >> sub, std::vector< Key > key, uint32_t val=0)
Node(internal::NoDupCheck, Fragment nt, std::vector< unsigned char > arg, uint32_t val=0)
WRAP_U will construct an or_i(X,0) node from the top constructed node.
size_t CalcScriptLen() const
Compute the length of the script for this miniscript (including children).
Ops(uint32_t in_count, MaxInt< uint32_t > in_sat, MaxInt< uint32_t > in_dsat)
ZERO_NOTEQUAL wraps the top constructed node with n:
[X] OP_NOTIF [Y] OP_ENDIF
std::optional< bool > has_duplicate_keys
Whether a public key appears more than once in this node.
WRAP_T will construct an and_v(X,1) node from the top constructed node.
ENDIF signals that we are inside some sort of OP_IF structure, which could be or_d, or_c, or_i, andor, d:, or j: wrapper, depending on what follows.
bool IsSane() const
Check whether this node is safe as a script on its own.
Node(const Ctx &ctx, Fragment nt, uint32_t val=0)
constexpr Type If(bool x) const
The empty type if x is false, itself otherwise.
NodeRef< Key > DecodeScript(I &in, I last, const Ctx &ctx)
Parse a miniscript from a bitcoin script.
AND_N will construct an andor(X,Y,0) node from the last two constructed nodes.
[X] OP_IFDUP OP_NOTIF [Y] OP_ENDIF
const Type typ
Cached expression type (computed by CalcType and fed through SanitizeType).
An expression which may be begin with wrappers followed by a colon.
const size_t scriptlen
Cached script length (computed by CalcScriptLen).
State
The various states a (txhash,peer) pair can be in.
CLOSE_BRACKET expects the next element to be ')' and fails if not.
const Fragment fragment
What node type this node is.
std::pair< opcodetype, std::vector< unsigned char > > Opcode
std::shared_ptr< const Node< Key > > NodeRef
[X1] ([Xn] OP_ADD)* [k] OP_EQUAL
ANDOR will construct an andor node from the last three constructed nodes.
Node(internal::NoDupCheck, Fragment nt, std::vector< NodeRef< Key >> sub, std::vector< Key > key, uint32_t val=0)
AND_B will construct an and_b node from the last two constructed nodes.
size_t ComputeScriptLen(Fragment fragment, Type sub0typ, size_t subsize, uint32_t k, size_t n_subs, size_t n_keys)
Helper function for Node::CalcScriptLen.
std::vector< typename std::common_type< Args... >::type > Vector(Args &&... args)
Construct a vector with the specified elements.
int FindNextChar(Span< const char > sp, const char m)
uint32_t count
Non-push opcodes.
constexpr bool operator==(Type x) const
Equality operator.
A single expression of type B, K, or V.
In a thresh expression, all sub-expressions other than the first are W-type, and end in OP_ADD...
uint32_t m_flags
Internal bitmap of properties (see ""_mst operator for details).
Type SanitizeType(Type e)
A helper sanitizer/checker for the output of CalcType.
internal::Ops CalcOps() const
std::vector< Byte > ParseHex(std::string_view str)
Parse the hex string into bytes (uint8_t or std::byte).
std::optional< std::vector< Opcode > > DecomposeScript(const CScript &script)
Decode a script into opcode/push pairs.
MaxInt< uint32_t > dsat
Number of keys in possibly executed OP_CHECKMULTISIG(VERIFY)s to dissatisfy.
A miniscript expression which does not begin with wrappers.
bool IsNonMalleable() const
Check whether this script can always be satisfied in a non-malleable way.
OP_IF [X] OP_ELSE [Y] OP_ENDIF.
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
[n] OP_CHECKSEQUENCEVERIFY
Node(const Ctx &ctx, Fragment nt, std::vector< NodeRef< Key >> sub, std::vector< unsigned char > arg, uint32_t val=0)
constexpr Type(uint32_t flags)
Internal constructor used by the ""_mst operator.
bool IsSaneSubexpression() const
Whether the apparent policy of this node matches its script semantics. Doesn't guarantee it is a safe...
friend int Compare(const Node< Key > &node1, const Node< Key > &node2)
Compare two miniscript subtrees, using a non-recursive algorithm.
bool CheckOpsLimit() const
Check the ops limit of this script against the consensus limit.
MAYBE_AND_V will check if the next part of the script could be a valid miniscript sub-expression...
static constexpr unsigned int MAX_STANDARD_P2WSH_SCRIPT_SIZE
The maximum size in bytes of a standard witnessScript.
static secp256k1_context * ctx
bool NeedsSignature() const
Check whether this script always needs a signature.
OR_C will construct an or_c node from the last two constructed nodes.
void BuildBack(Fragment nt, std::vector< NodeRef< Key >> &constructed, const bool reverse=false)
BuildBack pops the last two elements off constructed and wraps them in the specified Fragment...
static bool verify(const CScriptNum10 &bignum, const CScriptNum &scriptnum)
NON_ZERO wraps the top constructed node with j:
THRESH will read a wrapped expression, and then look for a COMMA.
OP_DUP OP_IF [X] OP_ENDIF.
constexpr Type operator &(Type x) const
Compute the type with the intersection of properties.
Class whose objects represent the maximum of a list of integers.
COMMA expects the next element to be ',' and fails if not.
size_t ScriptSize() const
Return the size of the script for this expression (faster than ToScript().size()).
OR_D will construct an or_d node from the last two constructed nodes.
THRESH_E constructs a thresh node from the appropriate number of constructed children.
Node(const Ctx &ctx, Fragment nt, std::vector< Key > key, uint32_t val=0)
NodeRef< Key > Parse(Span< const char > in, const Ctx &ctx)
Parse a miniscript from its textual descriptor form.
const std::vector< NodeRef< Key > > subs
Subexpressions (for WRAP_*/AND_*/OR_*/ANDOR/THRESH)
std::optional< std::string > ToString(const CTx &ctx) const
MaxInt< uint32_t > sat
Number of keys in possibly executed OP_CHECKMULTISIG(VERIFY)s to satisfy.
Node(internal::NoDupCheck, Fragment nt, std::vector< NodeRef< Key >> sub, uint32_t val=0)
constexpr C * begin() const noexcept
OP_SIZE OP_0NOTEQUAL OP_IF [X] OP_ENDIF.
const std::vector< Key > keys
The keys used by this expression (only for PK_K/PK_H/MULTI)
bool operator==(const Node< Key > &arg) const
Equality testing.
friend MaxInt< I > operator|(const MaxInt< I > &a, const MaxInt< I > &b)
constexpr Type operator|(Type x) const
Compute the type with the union of properties.
Node(internal::NoDupCheck, Fragment nt, std::vector< Key > key, uint32_t val=0)
OR_I will construct an or_i node from the last two constructed nodes.
Result TreeEval(State root_state, DownFn &&downfn, UpFn upfn) const
Like TreeEvalMaybe, but always produces a result.
bool ParseInt64(std::string_view str, int64_t *out)
Convert string to signed 64-bit integer with strict parse error feedback.
bool CheckStackSize() const
Check the maximum stack size for this script against the policy limit.
Node(const Ctx &ctx, Fragment nt, std::vector< NodeRef< Key >> sub, uint32_t val=0)
StackSize(MaxInt< uint32_t > in_sat, MaxInt< uint32_t > in_dsat)
Node(internal::NoDupCheck, Fragment nt, std::vector< NodeRef< Key >> sub, std::vector< unsigned char > arg, uint32_t val=0)
Serialized script, used inside transaction inputs and outputs.
static const int MAX_OPS_PER_SCRIPT
Fragment
The different node types in miniscript.
AND_V will construct an and_v node from the last two constructed nodes.
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)...
static constexpr unsigned int MAX_STANDARD_P2WSH_STACK_ITEMS
The maximum number of witness stack items in a standard P2WSH script.
NodeRef< Key > MakeNodeRef(Args &&... args)
Construct a miniscript node as a shared_ptr.
DUP_IF wraps the top constructed node with d:
const internal::StackSize ss
Cached stack size bounds.
bool IsValidTopLevel() const
Check whether this node is valid as a script on its own.
Node(internal::NoDupCheck, Fragment nt, uint32_t val=0)
OR_B will construct an or_b node from the last two constructed nodes.
uint32_t GetOps() const
Return the maximum number of ops needed to satisfy this script non-malleably.
OP_SIZE 32 OP_EQUALVERIFY OP_SHA256 [hash] OP_EQUAL.
void DuplicateKeyCheck(const Ctx &ctx) const
Update duplicate key information in this Node.
An expression of type W (a: or s: wrappers).
constexpr bool operator<(Type x) const
Comparison operator to enable use in sets/maps (total ordering incompatible with <<).
bool ValidSatisfactions() const
Whether successful non-malleable satisfactions are guaranteed to be valid.
A Span is an object that can refer to a contiguous sequence of objects.
Type GetType() const
Return the expression type.
NodeRef< typename Ctx::Key > FromScript(const CScript &script, const Ctx &ctx)
OP_SIZE 32 OP_EQUALVERIFY OP_HASH256 [hash] OP_EQUAL.
Result TreeEval(UpFn upfn) const
Like TreeEval, but without downfn or State type.
CONSTEXPR_IF_NOT_DEBUG Span< C > last(std::size_t count) const noexcept
If, inside an ENDIF context, we find an OP_ELSE, then we could be in either an or_i or an andor node...
This type encapsulates the miniscript type system properties.
const internal::Ops ops
Cached ops counts.
CScript ToScript(const Ctx &ctx) const
std::optional< int64_t > ParseScriptNumber(const Opcode &in)
Determine whether the passed pair (created by DecomposeScript) is pushing a number.
internal::StackSize CalcStackSize() const
bool CheckTimeLocksMix() const
Check whether there is no satisfaction path that contains both timelocks and heightlocks.