diff options
author | Antoine Poinsot <darosior@protonmail.com> | 2021-08-24 15:39:47 +0200 |
---|---|---|
committer | Antoine Poinsot <darosior@protonmail.com> | 2023-02-11 14:12:09 +0100 |
commit | 22c5b00345063bdeb8b6d3da8b5692d18f92bfb7 (patch) | |
tree | fe2b395a2da1b3bc93d0ab2bcc140d73713e1480 /src/script/miniscript.cpp | |
parent | d0b1f613c2a20b2de2878be2de19f827347dcc24 (diff) |
miniscript: satisfaction support
This introduces the logic to "sign for" a Miniscript.
Co-Authored-By: Pieter Wuille <pieter.wuille@gmail.com>
Diffstat (limited to 'src/script/miniscript.cpp')
-rw-r--r-- | src/script/miniscript.cpp | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/src/script/miniscript.cpp b/src/script/miniscript.cpp index cb4d4cb783..45aebe909a 100644 --- a/src/script/miniscript.cpp +++ b/src/script/miniscript.cpp @@ -279,6 +279,76 @@ size_t ComputeScriptLen(Fragment fragment, Type sub0typ, size_t subsize, uint32_ assert(false); } +InputStack& InputStack::SetAvailable(Availability avail) { + available = avail; + if (avail == Availability::NO) { + stack.clear(); + size = std::numeric_limits<size_t>::max(); + has_sig = false; + malleable = false; + non_canon = false; + } + return *this; +} + +InputStack& InputStack::SetWithSig() { + has_sig = true; + return *this; +} + +InputStack& InputStack::SetNonCanon() { + non_canon = true; + return *this; +} + +InputStack& InputStack::SetMalleable(bool x) { + malleable = x; + return *this; +} + +InputStack operator+(InputStack a, InputStack b) { + a.stack = Cat(std::move(a.stack), std::move(b.stack)); + if (a.available != Availability::NO && b.available != Availability::NO) a.size += b.size; + a.has_sig |= b.has_sig; + a.malleable |= b.malleable; + a.non_canon |= b.non_canon; + if (a.available == Availability::NO || b.available == Availability::NO) { + a.SetAvailable(Availability::NO); + } else if (a.available == Availability::MAYBE || b.available == Availability::MAYBE) { + a.SetAvailable(Availability::MAYBE); + } + return a; +} + +InputStack operator|(InputStack a, InputStack b) { + // If only one is invalid, pick the other one. If both are invalid, pick an arbitrary one. + if (a.available == Availability::NO) return b; + if (b.available == Availability::NO) return a; + // If only one of the solutions has a signature, we must pick the other one. + if (!a.has_sig && b.has_sig) return a; + if (!b.has_sig && a.has_sig) return b; + if (!a.has_sig && !b.has_sig) { + // If neither solution requires a signature, the result is inevitably malleable. + a.malleable = true; + b.malleable = true; + } else { + // If both options require a signature, prefer the non-malleable one. + if (b.malleable && !a.malleable) return a; + if (a.malleable && !b.malleable) return b; + } + // Between two malleable or two non-malleable solutions, pick the smaller one between + // YESes, and the bigger ones between MAYBEs. Prefer YES over MAYBE. + if (a.available == Availability::YES && b.available == Availability::YES) { + return std::move(a.size <= b.size ? a : b); + } else if (a.available == Availability::MAYBE && b.available == Availability::MAYBE) { + return std::move(a.size >= b.size ? a : b); + } else if (a.available == Availability::YES) { + return a; + } else { + return b; + } +} + std::optional<std::vector<Opcode>> DecomposeScript(const CScript& script) { std::vector<Opcode> out; |