Skip to content

Commit d9c7364

Browse files
committed
Merge bitcoin#34141: miniscript: Use Func and Expr when parsing keys, hashes, and locktimes
4b53cbd test: Test for musig() in various miniscript expressions (Ava Chow) ec0f47b miniscript: Using Func and Expr when parsing keys, hashes, and locktimes (Ava Chow) 6fd780d descriptors: Increment key_exp_index in ParsePubkey(Inner) (Ava Chow) b12281b miniscript: Use a reference to key_exp_index in KeyParser (Ava Chow) ce4c66e test: Test that key expression indexes match key count (Ava Chow) Pull request description: The miniscript parser currently only looks for the next `)` when parsing key, hash, and locktime expressions. This fails to parse when the expressions contain a nested expression. Currently, this is only possible with `musig()` inside of key expressions. However, this pattern can be generalized to handling hashes and locktimes, so I implemented those too. Fixes bitcoin#34076 ACKs for top commit: rkrux: ACK 4b53cbd sipa: ACK 4b53cbd darosior: Other than that, Approach ACK 4b53cbd. That makes sense to me but i have not closely reviewed the code. Tree-SHA512: 01040c7b07a59d8e3725ff11ab9543b256aea22535fb94059f490a5bb45319e859666af04c2f0a4edcb8cf1e6dfc7bd8a8271b21ad81143bafccd4d0a39cae9c
2 parents 6c8d628 + 4b53cbd commit d9c7364

9 files changed

Lines changed: 148 additions & 103 deletions

File tree

src/script/descriptor.cpp

Lines changed: 58 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -161,12 +161,11 @@ typedef std::vector<uint32_t> KeyPath;
161161
/** Interface for public key objects in descriptors. */
162162
struct PubkeyProvider
163163
{
164-
protected:
164+
public:
165165
//! Index of this key expression in the descriptor
166166
//! E.g. If this PubkeyProvider is key1 in multi(2, key1, key2, key3), then m_expr_index = 0
167-
uint32_t m_expr_index;
167+
const uint32_t m_expr_index;
168168

169-
public:
170169
explicit PubkeyProvider(uint32_t exp_index) : m_expr_index(exp_index) {}
171170

172171
virtual ~PubkeyProvider() = default;
@@ -229,6 +228,9 @@ struct PubkeyProvider
229228

230229
/** Whether this PubkeyProvider is a BIP 32 extended key that can be derived from */
231230
virtual bool IsBIP32() const = 0;
231+
232+
/** Get the count of keys known by this PubkeyProvider. Usually one, but may be more for key aggregation schemes */
233+
virtual size_t GetKeyCount() const { return 1; }
232234
};
233235

234236
class OriginPubkeyProvider final : public PubkeyProvider
@@ -788,6 +790,10 @@ class MuSigPubkeyProvider final : public PubkeyProvider
788790
// musig() can only be a BIP 32 key if all participants are bip32 too
789791
return std::all_of(m_participants.begin(), m_participants.end(), [](const auto& pubkey) { return pubkey->IsBIP32(); });
790792
}
793+
size_t GetKeyCount() const override
794+
{
795+
return 1 + m_participants.size();
796+
}
791797
};
792798

793799
/** Base class for all Descriptor implementations. */
@@ -1041,6 +1047,40 @@ class DescriptorImpl : public Descriptor
10411047
}
10421048
return all;
10431049
}
1050+
1051+
uint32_t GetMaxKeyExpr() const final
1052+
{
1053+
uint32_t max_key_expr{0};
1054+
std::vector<const DescriptorImpl*> todo = {this};
1055+
while (!todo.empty()) {
1056+
const DescriptorImpl* desc = todo.back();
1057+
todo.pop_back();
1058+
for (const auto& p : desc->m_pubkey_args) {
1059+
max_key_expr = std::max(max_key_expr, p->m_expr_index);
1060+
}
1061+
for (const auto& s : desc->m_subdescriptor_args) {
1062+
todo.push_back(s.get());
1063+
}
1064+
}
1065+
return max_key_expr;
1066+
}
1067+
1068+
size_t GetKeyCount() const final
1069+
{
1070+
size_t count{0};
1071+
std::vector<const DescriptorImpl*> todo = {this};
1072+
while (!todo.empty()) {
1073+
const DescriptorImpl* desc = todo.back();
1074+
todo.pop_back();
1075+
for (const auto& p : desc->m_pubkey_args) {
1076+
count += p->GetKeyCount();
1077+
}
1078+
for (const auto& s : desc->m_subdescriptor_args) {
1079+
todo.push_back(s.get());
1080+
}
1081+
}
1082+
return count;
1083+
}
10441084
};
10451085

10461086
/** A parsed addr(A) descriptor. */
@@ -1833,7 +1873,7 @@ static DeriveType ParseDeriveType(std::vector<std::span<const char>>& split, boo
18331873
}
18341874

18351875
/** Parse a public key that excludes origin information. */
1836-
std::vector<std::unique_ptr<PubkeyProvider>> ParsePubkeyInner(uint32_t key_exp_index, const std::span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, bool& apostrophe, std::string& error)
1876+
std::vector<std::unique_ptr<PubkeyProvider>> ParsePubkeyInner(uint32_t& key_exp_index, const std::span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, bool& apostrophe, std::string& error)
18371877
{
18381878
std::vector<std::unique_ptr<PubkeyProvider>> ret;
18391879
bool permit_uncompressed = ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH;
@@ -1858,6 +1898,7 @@ std::vector<std::unique_ptr<PubkeyProvider>> ParsePubkeyInner(uint32_t key_exp_i
18581898
if (pubkey.IsFullyValid()) {
18591899
if (permit_uncompressed || pubkey.IsCompressed()) {
18601900
ret.emplace_back(std::make_unique<ConstPubkeyProvider>(key_exp_index, pubkey, false));
1901+
++key_exp_index;
18611902
return ret;
18621903
} else {
18631904
error = "Uncompressed keys are not allowed";
@@ -1869,6 +1910,7 @@ std::vector<std::unique_ptr<PubkeyProvider>> ParsePubkeyInner(uint32_t key_exp_i
18691910
pubkey.Set(std::begin(fullkey), std::end(fullkey));
18701911
if (pubkey.IsFullyValid()) {
18711912
ret.emplace_back(std::make_unique<ConstPubkeyProvider>(key_exp_index, pubkey, true));
1913+
++key_exp_index;
18721914
return ret;
18731915
}
18741916
}
@@ -1881,6 +1923,7 @@ std::vector<std::unique_ptr<PubkeyProvider>> ParsePubkeyInner(uint32_t key_exp_i
18811923
CPubKey pubkey = key.GetPubKey();
18821924
out.keys.emplace(pubkey.GetID(), key);
18831925
ret.emplace_back(std::make_unique<ConstPubkeyProvider>(key_exp_index, pubkey, ctx == ParseScriptContext::P2TR));
1926+
++key_exp_index;
18841927
return ret;
18851928
} else {
18861929
error = "Uncompressed keys are not allowed";
@@ -1904,6 +1947,7 @@ std::vector<std::unique_ptr<PubkeyProvider>> ParsePubkeyInner(uint32_t key_exp_i
19041947
for (auto& path : paths) {
19051948
ret.emplace_back(std::make_unique<BIP32PubkeyProvider>(key_exp_index, extpubkey, std::move(path), type, apostrophe));
19061949
}
1950+
++key_exp_index;
19071951
return ret;
19081952
}
19091953

@@ -1961,7 +2005,6 @@ std::vector<std::unique_ptr<PubkeyProvider>> ParsePubkey(uint32_t& key_exp_index
19612005
max_multipath_len = std::max(max_multipath_len, pk.size());
19622006

19632007
providers.emplace_back(std::move(pk));
1964-
key_exp_index++;
19652008
}
19662009
if (!any_key_parsed) {
19672010
error = "musig(): Must contain key expressions";
@@ -2053,6 +2096,7 @@ std::vector<std::unique_ptr<PubkeyProvider>> ParsePubkey(uint32_t& key_exp_index
20532096
// No multipath derivation, MuSigPubkeyProvider uses the first (and only) participant pubkey providers, and the first (and only) path
20542097
emplace_final_provider(0, 0);
20552098
}
2099+
++key_exp_index; // Increment key expression index for the MuSigPubkeyProvider too
20562100
return ret;
20572101
}
20582102

@@ -2093,7 +2137,7 @@ std::vector<std::unique_ptr<PubkeyProvider>> ParsePubkey(uint32_t& key_exp_index
20932137
if (providers.empty()) return {};
20942138
ret.reserve(providers.size());
20952139
for (auto& prov : providers) {
2096-
ret.emplace_back(std::make_unique<OriginPubkeyProvider>(key_exp_index, info, std::move(prov), apostrophe));
2140+
ret.emplace_back(std::make_unique<OriginPubkeyProvider>(prov->m_expr_index, info, std::move(prov), apostrophe));
20972141
}
20982142
return ret;
20992143
}
@@ -2143,12 +2187,12 @@ struct KeyParser {
21432187
mutable std::string m_key_parsing_error;
21442188
//! The script context we're operating within (Tapscript or P2WSH).
21452189
const miniscript::MiniscriptContext m_script_ctx;
2146-
//! The number of keys that were parsed before starting to parse this Miniscript descriptor.
2147-
uint32_t m_offset;
2190+
//! The current key expression index
2191+
uint32_t& m_expr_index;
21482192

21492193
KeyParser(FlatSigningProvider* out LIFETIMEBOUND, const SigningProvider* in LIFETIMEBOUND,
2150-
miniscript::MiniscriptContext ctx, uint32_t offset = 0)
2151-
: m_out(out), m_in(in), m_script_ctx(ctx), m_offset(offset) {}
2194+
miniscript::MiniscriptContext ctx, uint32_t& key_exp_index LIFETIMEBOUND)
2195+
: m_out(out), m_in(in), m_script_ctx(ctx), m_expr_index(key_exp_index) {}
21522196

21532197
bool KeyCompare(const Key& a, const Key& b) const {
21542198
return *m_keys.at(a).at(0) < *m_keys.at(b).at(0);
@@ -2162,12 +2206,11 @@ struct KeyParser {
21622206
assert(false);
21632207
}
21642208

2165-
template<typename I> std::optional<Key> FromString(I begin, I end) const
2209+
std::optional<Key> FromString(std::span<const char>& in) const
21662210
{
21672211
assert(m_out);
21682212
Key key = m_keys.size();
2169-
uint32_t exp_index = m_offset + key;
2170-
auto pk = ParsePubkey(exp_index, {&*begin, &*end}, ParseContext(), *m_out, m_key_parsing_error);
2213+
auto pk = ParsePubkey(m_expr_index, in, ParseContext(), *m_out, m_key_parsing_error);
21712214
if (pk.empty()) return {};
21722215
m_keys.emplace_back(std::move(pk));
21732216
return key;
@@ -2239,7 +2282,6 @@ std::vector<std::unique_ptr<DescriptorImpl>> ParseScript(uint32_t& key_exp_index
22392282
error = strprintf("pk(): %s", error);
22402283
return {};
22412284
}
2242-
++key_exp_index;
22432285
for (auto& pubkey : pubkeys) {
22442286
ret.emplace_back(std::make_unique<PKDescriptor>(std::move(pubkey), ctx == ParseScriptContext::P2TR));
22452287
}
@@ -2251,7 +2293,6 @@ std::vector<std::unique_ptr<DescriptorImpl>> ParseScript(uint32_t& key_exp_index
22512293
error = strprintf("pkh(): %s", error);
22522294
return {};
22532295
}
2254-
++key_exp_index;
22552296
for (auto& pubkey : pubkeys) {
22562297
ret.emplace_back(std::make_unique<PKHDescriptor>(std::move(pubkey)));
22572298
}
@@ -2263,7 +2304,6 @@ std::vector<std::unique_ptr<DescriptorImpl>> ParseScript(uint32_t& key_exp_index
22632304
error = strprintf("combo(): %s", error);
22642305
return {};
22652306
}
2266-
++key_exp_index;
22672307
for (auto& pubkey : pubkeys) {
22682308
ret.emplace_back(std::make_unique<ComboDescriptor>(std::move(pubkey)));
22692309
}
@@ -2303,7 +2343,6 @@ std::vector<std::unique_ptr<DescriptorImpl>> ParseScript(uint32_t& key_exp_index
23032343
script_size += pks.at(0)->GetSize() + 1;
23042344
max_providers_len = std::max(max_providers_len, pks.size());
23052345
providers.emplace_back(std::move(pks));
2306-
key_exp_index++;
23072346
}
23082347
if ((multi || sortedmulti) && (providers.empty() || providers.size() > MAX_PUBKEYS_PER_MULTISIG)) {
23092348
error = strprintf("Cannot have %u keys in multisig; must have between 1 and %d keys, inclusive", providers.size(), MAX_PUBKEYS_PER_MULTISIG);
@@ -2373,7 +2412,6 @@ std::vector<std::unique_ptr<DescriptorImpl>> ParseScript(uint32_t& key_exp_index
23732412
error = strprintf("wpkh(): %s", error);
23742413
return {};
23752414
}
2376-
key_exp_index++;
23772415
for (auto& pubkey : pubkeys) {
23782416
ret.emplace_back(std::make_unique<WPKHDescriptor>(std::move(pubkey)));
23792417
}
@@ -2426,7 +2464,6 @@ std::vector<std::unique_ptr<DescriptorImpl>> ParseScript(uint32_t& key_exp_index
24262464
return {};
24272465
}
24282466
size_t max_providers_len = internal_keys.size();
2429-
++key_exp_index;
24302467
std::vector<std::vector<std::unique_ptr<DescriptorImpl>>> subscripts; //!< list of multipath expanded script subexpressions
24312468
std::vector<int> depths; //!< depth in the tree of each subexpression (same length subscripts)
24322469
if (expr.size()) {
@@ -2530,7 +2567,6 @@ std::vector<std::unique_ptr<DescriptorImpl>> ParseScript(uint32_t& key_exp_index
25302567
error = strprintf("rawtr(): %s", error);
25312568
return {};
25322569
}
2533-
++key_exp_index;
25342570
for (auto& pubkey : output_keys) {
25352571
ret.emplace_back(std::make_unique<RawTRDescriptor>(std::move(pubkey)));
25362572
}
@@ -2594,7 +2630,6 @@ std::vector<std::unique_ptr<DescriptorImpl>> ParseScript(uint32_t& key_exp_index
25942630
// A signature check is required for a miniscript to be sane. Therefore no sane miniscript
25952631
// may have an empty list of public keys.
25962632
CHECK_NONFATAL(!parser.m_keys.empty());
2597-
key_exp_index += parser.m_keys.size();
25982633
// Make sure all vecs are of the same length, or exactly length 1
25992634
// For length 1 vectors, clone subdescs until vector is the same length
26002635
size_t num_multipath = std::max_element(parser.m_keys.begin(), parser.m_keys.end(),
@@ -2769,7 +2804,8 @@ std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptCo
27692804

27702805
if (ctx == ParseScriptContext::P2WSH || ctx == ParseScriptContext::P2TR) {
27712806
const auto script_ctx{ctx == ParseScriptContext::P2WSH ? miniscript::MiniscriptContext::P2WSH : miniscript::MiniscriptContext::TAPSCRIPT};
2772-
KeyParser parser(/* out = */nullptr, /* in = */&provider, /* ctx = */script_ctx);
2807+
uint32_t key_exp_index = 0;
2808+
KeyParser parser(/* out = */nullptr, /* in = */&provider, /* ctx = */script_ctx, key_exp_index);
27732809
auto node = miniscript::FromScript(script, parser);
27742810
if (node && node->IsSane()) {
27752811
std::vector<std::unique_ptr<PubkeyProvider>> keys;

src/script/descriptor.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,12 @@ struct Descriptor {
181181

182182
/** Semantic/safety warnings (includes subdescriptors). */
183183
virtual std::vector<std::string> Warnings() const = 0;
184+
185+
/** Get the maximum key expression index. Used only for tests */
186+
virtual uint32_t GetMaxKeyExpr() const = 0;
187+
188+
/** Get the number of key expressions in this descriptor. Used only for tests */
189+
virtual size_t GetKeyCount() const = 0;
184190
};
185191

186192
/** Parse a `descriptor` string. Included private keys are put in `out`.

0 commit comments

Comments
 (0)