aboutsummaryrefslogtreecommitdiff
path: root/src/script/miniscript.cpp
diff options
context:
space:
mode:
authorAntoine Poinsot <darosior@protonmail.com>2023-01-21 13:52:23 +0100
committerAntoine Poinsot <darosior@protonmail.com>2023-10-08 02:43:15 +0200
commit687a0b0fa53ddd5632287b9e00ad8b0550830287 (patch)
tree0eac61f341a97fb9b8903c0887ce98cca3a6b770 /src/script/miniscript.cpp
parent9164c2eca164d78cbae5351d383f39320711efb9 (diff)
miniscript: introduce a multi_a fragment
It is the equivalent of multi() but for Tapscript, using CHECKSIGADD instead of CHECKMULTISIG. It shares the same properties as multi() but for 'n', since a threshold multi_a() may have an empty vector as the top element of its satisfaction. It could also have the 'o' property when it only has a single key, but in this case a 'pk()' is always preferable anyways.
Diffstat (limited to 'src/script/miniscript.cpp')
-rw-r--r--src/script/miniscript.cpp14
1 files changed, 11 insertions, 3 deletions
diff --git a/src/script/miniscript.cpp b/src/script/miniscript.cpp
index 28c79eab30..82f65e5dde 100644
--- a/src/script/miniscript.cpp
+++ b/src/script/miniscript.cpp
@@ -45,7 +45,7 @@ Type ComputeType(Fragment fragment, Type x, Type y, Type z, const std::vector<Ty
// Sanity check on k
if (fragment == Fragment::OLDER || fragment == Fragment::AFTER) {
assert(k >= 1 && k < 0x80000000UL);
- } else if (fragment == Fragment::MULTI) {
+ } else if (fragment == Fragment::MULTI || fragment == Fragment::MULTI_A) {
assert(k >= 1 && k <= n_keys);
} else if (fragment == Fragment::THRESH) {
assert(k >= 1 && k <= n_subs);
@@ -69,7 +69,9 @@ Type ComputeType(Fragment fragment, Type x, Type y, Type z, const std::vector<Ty
if (fragment == Fragment::PK_K || fragment == Fragment::PK_H) {
assert(n_keys == 1);
} else if (fragment == Fragment::MULTI) {
- assert(n_keys >= 1 && n_keys <= 20);
+ assert(n_keys >= 1 && n_keys <= MAX_PUBKEYS_PER_MULTISIG);
+ } else if (fragment == Fragment::MULTI_A) {
+ assert(n_keys >= 1 && n_keys <= MAX_PUBKEYS_PER_MULTI_A);
} else {
assert(n_keys == 0);
}
@@ -212,6 +214,7 @@ Type ComputeType(Fragment fragment, Type x, Type y, Type z, const std::vector<Ty
((x << "i"_mst) && (y << "j"_mst)) ||
((x << "j"_mst) && (y << "i"_mst)))); // k=k_x*k_y*k_z* !(g_x*h_y + h_x*g_y + i_x*j_y + j_x*i_y)
case Fragment::MULTI: return "Bnudemsk"_mst;
+ case Fragment::MULTI_A: return "Budemsk"_mst;
case Fragment::THRESH: {
bool all_e = true;
bool all_m = true;
@@ -260,6 +263,7 @@ size_t ComputeScriptLen(Fragment fragment, Type sub0typ, size_t subsize, uint32_
case Fragment::HASH160:
case Fragment::RIPEMD160: return 4 + 2 + 21;
case Fragment::MULTI: return 1 + BuildScript(n_keys).size() + BuildScript(k).size() + 34 * n_keys;
+ case Fragment::MULTI_A: return (1 + 32 + 1) * n_keys + BuildScript(k).size() + 1;
case Fragment::AND_V: return subsize;
case Fragment::WRAP_V: return subsize + (sub0typ << "x"_mst);
case Fragment::WRAP_S:
@@ -373,9 +377,13 @@ std::optional<std::vector<Opcode>> DecomposeScript(const CScript& script)
// Decompose OP_EQUALVERIFY into OP_EQUAL OP_VERIFY
out.emplace_back(OP_EQUAL, std::vector<unsigned char>());
opcode = OP_VERIFY;
+ } else if (opcode == OP_NUMEQUALVERIFY) {
+ // Decompose OP_NUMEQUALVERIFY into OP_NUMEQUAL OP_VERIFY
+ out.emplace_back(OP_NUMEQUAL, std::vector<unsigned char>());
+ opcode = OP_VERIFY;
} else if (IsPushdataOp(opcode)) {
if (!CheckMinimalPush(push_data, opcode)) return {};
- } else if (it != itend && (opcode == OP_CHECKSIG || opcode == OP_CHECKMULTISIG || opcode == OP_EQUAL) && (*it == OP_VERIFY)) {
+ } else if (it != itend && (opcode == OP_CHECKSIG || opcode == OP_CHECKMULTISIG || opcode == OP_EQUAL || opcode == OP_NUMEQUAL) && (*it == OP_VERIFY)) {
// Rule out non minimal VERIFY sequences
return {};
}