Summary
Many callsites only need to determine the script type and don’t use the parsed solutions.
Previously, these callers still incurred the cost of allocating and populating a std::vector<std::vector<unsigned char>>.
Fix
Changing Solver signature from reference to nullable pointer parameter with nullptr default allows calling the method for its result only. Note that we can’t call std::optional here because that would copy the values but we need the result to be provided from the outside to avoid the copies.
Inside the Solver we guard all accesses to the solutions parameter.
Callsites were changed to pass &solutions only when they need the data and removed when we don’t.
Origin & Alternative
This was originally discovered in https://github.com/bitcoin/bitcoin/pull/32279/files#diff-060e8fd790fc1c3e18c64327a7395bb5b2d6d57db9792cc666bd8d7354a40c0bR1154-R1159 where we needed to test the allocation characteristics of different templates. This supersedes the vector reuse optimization approach in #33645 (comment) by addressing the problem more fundamentally - avoiding unnecessary work entirely rather than optimizing it. The author of the different change was added as a coauthor.