MCPcopy Create free account
hub / github.com/bitcoin/bitcoin / Parse

Function Parse

src/script/miniscript.h:1856–2213  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

1854 */
1855template <typename Key, typename Ctx>
1856inline std::optional<Node<Key>> Parse(std::span<const char> in, const Ctx& ctx)
1857{
1858 using namespace script;
1859
1860 // Account for the minimum script size for all parsed fragments so far. It "borrows" 1
1861 // script byte from all leaf nodes, counting it instead whenever a space for a recursive
1862 // expression is added (through andor, and_*, or_*, thresh). This guarantees that all fragments
1863 // increment the script_size by at least one, except for:
1864 // - "0", "1": these leafs are only a single byte, so their subtracted-from increment is 0.
1865 // This is not an issue however, as "space" for them has to be created by combinators,
1866 // which do increment script_size.
1867 // - "v:": the v wrapper adds nothing as in some cases it results in no opcode being added
1868 // (instead transforming another opcode into its VERIFY form). However, the v: wrapper has
1869 // to be interleaved with other fragments to be valid, so this is not a concern.
1870 size_t script_size{1};
1871 size_t max_size{internal::MaxScriptSize(ctx.MsContext())};
1872
1873 // The two integers are used to hold state for thresh()
1874 std::vector<std::tuple<ParseContext, int64_t, int64_t>> to_parse;
1875 std::vector<Node<Key>> constructed;
1876
1877 to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1);
1878
1879 // Parses a multi() or multi_a() from its string representation. Returns false on parsing error.
1880 const auto parse_multi_exp = [&](std::span<const char>& in, const bool is_multi_a) -> bool {
1881 const auto max_keys{is_multi_a ? MAX_PUBKEYS_PER_MULTI_A : MAX_PUBKEYS_PER_MULTISIG};
1882 const auto required_ctx{is_multi_a ? MiniscriptContext::TAPSCRIPT : MiniscriptContext::P2WSH};
1883 if (ctx.MsContext() != required_ctx) return false;
1884 // Get threshold
1885 int next_comma = FindNextChar(in, ',');
1886 if (next_comma < 1) return false;
1887 const auto k_to_integral{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
1888 if (!k_to_integral.has_value()) return false;
1889 const int64_t k{k_to_integral.value()};
1890 in = in.subspan(next_comma + 1);
1891 // Get keys. It is compatible for both compressed and x-only keys.
1892 std::vector<Key> keys;
1893 while (next_comma != -1) {
1894 next_comma = FindNextChar(in, ',');
1895 int key_length = (next_comma == -1) ? FindNextChar(in, ')') : next_comma;
1896 if (key_length < 1) return false;
1897 std::span<const char> sp{in.begin(), in.begin() + key_length};
1898 auto key = ctx.FromString(sp);
1899 if (!key) return false;
1900 keys.push_back(std::move(*key));
1901 in = in.subspan(key_length + 1);
1902 }
1903 if (keys.size() < 1 || keys.size() > max_keys) return false;
1904 if (k < 1 || k > (int64_t)keys.size()) return false;
1905 if (is_multi_a) {
1906 // (push + xonly-key + CHECKSIG[ADD]) * n + k + OP_NUMEQUAL(VERIFY), minus one.
1907 script_size += (1 + 32 + 1) * keys.size() + BuildScript(k).size();
1908 constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI_A, std::move(keys), k);
1909 } else {
1910 script_size += 2 + (keys.size() > 16) + (k > 16) + 34 * keys.size();
1911 constructed.emplace_back(internal::NoDupCheck{}, ctx.MsContext(), Fragment::MULTI, std::move(keys), k);
1912 }
1913 return true;

Callers

nothing calls this directly

Calls 15

MaxScriptSizeFunction · 0.85
FindNextCharFunction · 0.85
BuildScriptFunction · 0.85
ConstFunction · 0.85
VectorFunction · 0.85
IsTapscriptFunction · 0.85
ParseHexStrFunction · 0.85
ExprFunction · 0.85
FuncFunction · 0.85
BuildBackFunction · 0.85
DuplicateKeyCheckMethod · 0.80
MsContextMethod · 0.45

Tested by

no test coverage detected