Bitcoin Core  31.0.0
P2P Digital Currency
descriptor_parse.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-present The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include <chainparams.h>
6 #include <key_io.h>
7 #include <pubkey.h>
8 #include <script/descriptor.h>
9 #include <test/fuzz/fuzz.h>
11 #include <util/chaintype.h>
12 #include <util/strencodings.h>
13 
16 
18 static void TestDescriptor(const Descriptor& desc, FlatSigningProvider& sig_provider, std::string& dummy, std::optional<bool>& is_ranged, std::optional<bool>& is_solvable)
19 {
20  // Trivial helpers.
21  (void)desc.IsRange();
22  (void)desc.IsSingleType();
23  (void)desc.GetOutputType();
24 
25  if (is_ranged.has_value()) {
26  assert(desc.IsRange() == *is_ranged);
27  } else {
28  is_ranged = desc.IsRange();
29  }
30  if (is_solvable.has_value()) {
31  assert(desc.IsSolvable() == *is_solvable);
32  } else {
33  is_solvable = desc.IsSolvable();
34  }
35 
36  // Serialization to string representation.
37  (void)desc.ToString();
38  (void)desc.ToPrivateString(sig_provider, dummy);
39  (void)desc.ToNormalizedString(sig_provider, dummy);
40 
41  // Serialization to Script.
42  DescriptorCache cache;
43  std::vector<CScript> out_scripts;
44  (void)desc.Expand(0, sig_provider, out_scripts, sig_provider, &cache);
45  (void)desc.ExpandPrivate(0, sig_provider, sig_provider);
46  (void)desc.ExpandFromCache(0, cache, out_scripts, sig_provider);
47 
48  // If we could serialize to script we must be able to infer using the same provider.
49  if (!out_scripts.empty()) {
50  assert(InferDescriptor(out_scripts.back(), sig_provider));
51 
52  // The ScriptSize() must match the size of the serialized Script. (ScriptSize() is set for all descs but 'combo()'.)
53  const bool is_combo{!desc.IsSingleType()};
54  assert(is_combo || desc.ScriptSize() == out_scripts.back().size());
55  }
56 
57  const auto max_sat_maxsig{desc.MaxSatisfactionWeight(true)};
58  const auto max_sat_nonmaxsig{desc.MaxSatisfactionWeight(true)};
59  const auto max_elems{desc.MaxSatisfactionElems()};
60  // We must be able to estimate the max satisfaction size for any solvable descriptor (but combo).
61  const bool is_nontop_or_nonsolvable{!*is_solvable || !desc.GetOutputType()};
62  const bool is_input_size_info_set{max_sat_maxsig && max_sat_nonmaxsig && max_elems};
63  assert(is_input_size_info_set || is_nontop_or_nonsolvable);
64 
65  auto max_key_expr = desc.GetMaxKeyExpr();
66  auto key_count = desc.GetKeyCount();
67  assert((max_key_expr == 0 && key_count == 0) || max_key_expr + 1 == key_count);
68 }
69 
71 {
72  static ECC_Context ecc_context{};
74 }
75 
77 {
80 }
81 
83 {
84  const std::string mocked_descriptor{buffer.begin(), buffer.end()};
85  if (const auto descriptor = MOCKED_DESC_CONVERTER.GetDescriptor(mocked_descriptor)) {
86  if (IsTooExpensive(MakeUCharSpan(*descriptor))) return;
87  FlatSigningProvider signing_provider;
88  std::string error;
89  const auto desc = Parse(*descriptor, signing_provider, error);
90  std::optional<bool> is_ranged;
91  std::optional<bool> is_solvable;
92  for (const auto& d : desc) {
93  assert(d);
94  TestDescriptor(*d, signing_provider, error, is_ranged, is_solvable);
95  }
96  }
97 }
98 
100 {
101  if (IsTooExpensive(buffer)) return;
102 
103  const std::string descriptor(buffer.begin(), buffer.end());
104  FlatSigningProvider signing_provider;
105  std::string error;
106  for (const bool require_checksum : {true, false}) {
107  const auto desc = Parse(descriptor, signing_provider, error, require_checksum);
108  std::optional<bool> is_ranged;
109  std::optional<bool> is_solvable;
110  for (const auto& d : desc) {
111  assert(d);
112  TestDescriptor(*d, signing_provider, error, is_ranged, is_solvable);
113  }
114  }
115 }
static UniValue Parse(std::string_view raw, ParamFormat format=ParamFormat::JSON)
Parse string to UniValue or throw runtime_error if string contains invalid JSON.
Definition: client.cpp:395
virtual std::optional< int64_t > MaxSatisfactionWeight(bool use_max_sig) const =0
Get the maximum size of a satisfaction for this descriptor, in weight units.
bool IsTooExpensive(std::span< const uint8_t > buffer)
Deriving "expensive" descriptors will consume useful fuzz compute. The compute is better spent on a s...
Definition: descriptor.h:94
virtual bool IsSingleType() const =0
Whether this descriptor will return one scriptPubKey or multiple (aka is or is not combo) ...
constexpr auto MakeUCharSpan(const V &v) -> decltype(UCharSpanCast(std::span
Like the std::span constructor, but for (const) unsigned char member types only.
Definition: span.h:111
static void TestDescriptor(const Descriptor &desc, FlatSigningProvider &sig_provider, std::string &dummy, std::optional< bool > &is_ranged, std::optional< bool > &is_solvable)
Test a successfully parsed descriptor.
assert(!tx.IsCoinBase())
RAII class initializing and deinitializing global state for elliptic curve support.
Definition: key.h:325
ECC_Context ecc_context
virtual bool IsSolvable() const =0
Whether this descriptor has all information about signing ignoring lack of private keys...
std::unique_ptr< Descriptor > InferDescriptor(const CScript &script, const SigningProvider &provider)
Find a descriptor for the specified script, using information from provider where possible...
virtual bool ExpandFromCache(int pos, const DescriptorCache &read_cache, std::vector< CScript > &output_scripts, FlatSigningProvider &out) const =0
Expand a descriptor at a specified position using cached expansion data.
FUZZ_TARGET(mocked_descriptor_parse,.init=initialize_mocked_descriptor_parse)
virtual void ExpandPrivate(int pos, const SigningProvider &provider, FlatSigningProvider &out) const =0
Expand the private key for a descriptor at a specified position, if possible.
virtual uint32_t GetMaxKeyExpr() const =0
Get the maximum key expression index.
virtual bool ToNormalizedString(const SigningProvider &provider, std::string &out, const DescriptorCache *cache=nullptr) const =0
Convert the descriptor to a normalized string.
void Init()
When initializing the target, populate the list of keys.
Definition: descriptor.cpp:17
void initialize_descriptor_parse()
virtual std::optional< int64_t > MaxSatisfactionElems() const =0
Get the maximum size number of stack elements for satisfying this descriptor.
virtual size_t GetKeyCount() const =0
Get the number of key expressions in this descriptor.
std::optional< std::string > GetDescriptor(std::string_view mocked_desc) const
Get an actual descriptor string from a descriptor string whose keys were mocked.
Definition: descriptor.cpp:59
void initialize_mocked_descriptor_parse()
virtual std::optional< int64_t > ScriptSize() const =0
Get the size of the scriptPubKey for this descriptor.
virtual bool Expand(int pos, const SigningProvider &provider, std::vector< CScript > &output_scripts, FlatSigningProvider &out, DescriptorCache *write_cache=nullptr) const =0
Expand a descriptor at a specified position.
Converts a mocked descriptor string to a valid one.
Definition: descriptor.h:23
Cache for single descriptor&#39;s derived extended pubkeys.
Definition: descriptor.h:19
MockedDescriptorConverter MOCKED_DESC_CONVERTER
The converter of mocked descriptors, needs to be initialized when the target is.
virtual bool IsRange() const =0
Whether the expansion of this descriptor depends on the position.
virtual std::optional< OutputType > GetOutputType() const =0
virtual std::string ToString(bool compat_format=false) const =0
Convert the descriptor back to a string, undoing parsing.
virtual bool ToPrivateString(const SigningProvider &provider, std::string &out) const =0
Convert the descriptor to a private string.
void SelectParams(const ChainType chain)
Sets the params returned by Params() to those for the given chain type.
Interface for parsed descriptor objects.
Definition: descriptor.h:98