| 2296 | //! Parse a miniscript from a bitcoin script |
| 2297 | template <typename Key, typename Ctx, typename I> |
| 2298 | inline std::optional<Node<Key>> DecodeScript(I& in, I last, const Ctx& ctx) |
| 2299 | { |
| 2300 | // The two integers are used to hold state for thresh() |
| 2301 | std::vector<std::tuple<DecodeContext, int64_t, int64_t>> to_parse; |
| 2302 | std::vector<Node<Key>> constructed; |
| 2303 | |
| 2304 | // This is the top level, so we assume the type is B |
| 2305 | // (in particular, disallowing top level W expressions) |
| 2306 | to_parse.emplace_back(DecodeContext::BKV_EXPR, -1, -1); |
| 2307 | |
| 2308 | while (!to_parse.empty()) { |
| 2309 | // Exit early if the Miniscript is not going to be valid. |
| 2310 | if (!constructed.empty() && !constructed.back().IsValid()) return {}; |
| 2311 | |
| 2312 | // Get the current context we are decoding within |
| 2313 | auto [cur_context, n, k] = to_parse.back(); |
| 2314 | to_parse.pop_back(); |
| 2315 | |
| 2316 | switch(cur_context) { |
| 2317 | case DecodeContext::SINGLE_BKV_EXPR: { |
| 2318 | if (in >= last) return {}; |
| 2319 | |
| 2320 | // Constants |
| 2321 | if (in[0].first == OP_1) { |
| 2322 | ++in; |
| 2323 | constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_1); |
| 2324 | break; |
| 2325 | } |
| 2326 | if (in[0].first == OP_0) { |
| 2327 | ++in; |
| 2328 | constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::JUST_0); |
| 2329 | break; |
| 2330 | } |
| 2331 | // Public keys |
| 2332 | if (in[0].second.size() == 33 || in[0].second.size() == 32) { |
| 2333 | auto key = ctx.FromPKBytes(in[0].second.begin(), in[0].second.end()); |
| 2334 | if (!key) return {}; |
| 2335 | ++in; |
| 2336 | constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_K, Vector(std::move(*key))); |
| 2337 | break; |
| 2338 | } |
| 2339 | if (last - in >= 5 && in[0].first == OP_VERIFY && in[1].first == OP_EQUAL && in[3].first == OP_HASH160 && in[4].first == OP_DUP && in[2].second.size() == 20) { |
| 2340 | auto key = ctx.FromPKHBytes(in[2].second.begin(), in[2].second.end()); |
| 2341 | if (!key) return {}; |
| 2342 | in += 5; |
| 2343 | constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::PK_H, Vector(std::move(*key))); |
| 2344 | break; |
| 2345 | } |
| 2346 | // Time locks |
| 2347 | std::optional<int64_t> num; |
| 2348 | if (last - in >= 2 && in[0].first == OP_CHECKSEQUENCEVERIFY && (num = ParseScriptNumber(in[1]))) { |
| 2349 | in += 2; |
| 2350 | if (*num < 1 || *num > 0x7FFFFFFFL) return {}; |
| 2351 | constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num); |
| 2352 | break; |
| 2353 | } |
| 2354 | if (last - in >= 2 && in[0].first == OP_CHECKLOCKTIMEVERIFY && (num = ParseScriptNumber(in[1]))) { |
| 2355 | in += 2; |
nothing calls this directly
no test coverage detected