test: Test that key expression indexes match key count

This commit is contained in:
Ava Chow 2026-01-20 12:54:12 -08:00
parent 4f85b05131
commit ce4c66eb7c
5 changed files with 63 additions and 3 deletions

View File

@ -161,12 +161,11 @@ typedef std::vector<uint32_t> KeyPath;
/** Interface for public key objects in descriptors. */
struct PubkeyProvider
{
protected:
public:
//! Index of this key expression in the descriptor
//! E.g. If this PubkeyProvider is key1 in multi(2, key1, key2, key3), then m_expr_index = 0
uint32_t m_expr_index;
const uint32_t m_expr_index;
public:
explicit PubkeyProvider(uint32_t exp_index) : m_expr_index(exp_index) {}
virtual ~PubkeyProvider() = default;
@ -229,6 +228,9 @@ public:
/** Whether this PubkeyProvider is a BIP 32 extended key that can be derived from */
virtual bool IsBIP32() const = 0;
/** Get the count of keys known by this PubkeyProvider. Usually one, but may be more for key aggregation schemes */
virtual size_t GetKeyCount() const { return 1; }
};
class OriginPubkeyProvider final : public PubkeyProvider
@ -788,6 +790,10 @@ public:
// musig() can only be a BIP 32 key if all participants are bip32 too
return std::all_of(m_participants.begin(), m_participants.end(), [](const auto& pubkey) { return pubkey->IsBIP32(); });
}
size_t GetKeyCount() const override
{
return 1 + m_participants.size();
}
};
/** Base class for all Descriptor implementations. */
@ -1041,6 +1047,40 @@ public:
}
return all;
}
uint32_t GetMaxKeyExpr() const final
{
uint32_t max_key_expr{0};
std::vector<const DescriptorImpl*> todo = {this};
while (!todo.empty()) {
const DescriptorImpl* desc = todo.back();
todo.pop_back();
for (const auto& p : desc->m_pubkey_args) {
max_key_expr = std::max(max_key_expr, p->m_expr_index);
}
for (const auto& s : desc->m_subdescriptor_args) {
todo.push_back(s.get());
}
}
return max_key_expr;
}
size_t GetKeyCount() const final
{
size_t count{0};
std::vector<const DescriptorImpl*> todo = {this};
while (!todo.empty()) {
const DescriptorImpl* desc = todo.back();
todo.pop_back();
for (const auto& p : desc->m_pubkey_args) {
count += p->GetKeyCount();
}
for (const auto& s : desc->m_subdescriptor_args) {
todo.push_back(s.get());
}
}
return count;
}
};
/** A parsed addr(A) descriptor. */

View File

@ -181,6 +181,12 @@ struct Descriptor {
/** Semantic/safety warnings (includes subdescriptors). */
virtual std::vector<std::string> Warnings() const = 0;
/** Get the maximum key expression index. Used only for tests */
virtual uint32_t GetMaxKeyExpr() const = 0;
/** Get the number of key expressions in this descriptor. Used only for tests */
virtual size_t GetKeyCount() const = 0;
};
/** Parse a `descriptor` string. Included private keys are put in `out`.

View File

@ -283,6 +283,14 @@ void DoCheck(std::string prv, std::string pub, const std::string& norm_pub, int
BOOST_CHECK_EQUAL(parse_pub->IsRange(), (flags & RANGE) != 0);
BOOST_CHECK_EQUAL(parse_priv->IsRange(), (flags & RANGE) != 0);
// Check that the highest key expression index matches the number of keys in the descriptor
BOOST_TEST_INFO("Pub desc: " + pub);
uint32_t key_exprs = parse_pub->GetMaxKeyExpr();
BOOST_CHECK_EQUAL(key_exprs + 1, parse_pub->GetKeyCount());
BOOST_TEST_INFO("Priv desc: " + prv);
BOOST_CHECK_EQUAL(key_exprs, parse_priv->GetMaxKeyExpr());
BOOST_CHECK_EQUAL(key_exprs + 1, parse_priv->GetKeyCount());
// * For ranged descriptors, the `scripts` parameter is a list of expected result outputs, for subsequent
// positions to evaluate the descriptors on (so the first element of `scripts` is for evaluating the
// descriptor at 0; the second at 1; and so on). To verify this, we evaluate the descriptors once for

View File

@ -61,6 +61,10 @@ static void TestDescriptor(const Descriptor& desc, FlatSigningProvider& sig_prov
const bool is_nontop_or_nonsolvable{!*is_solvable || !desc.GetOutputType()};
const bool is_input_size_info_set{max_sat_maxsig && max_sat_nonmaxsig && max_elems};
assert(is_input_size_info_set || is_nontop_or_nonsolvable);
auto max_key_expr = desc.GetMaxKeyExpr();
auto key_count = desc.GetKeyCount();
assert((max_key_expr == 0 && key_count == 0) || max_key_expr + 1 == key_count);
}
void initialize_descriptor_parse()

View File

@ -37,6 +37,8 @@ public:
std::optional<int64_t> MaxSatisfactionElems() const override { return {}; }
void GetPubKeys(std::set<CPubKey>& pubkeys, std::set<CExtPubKey>& ext_pubs) const override {}
std::vector<std::string> Warnings() const override { return {}; }
uint32_t GetMaxKeyExpr() const override { return 0; }
size_t GetKeyCount() const override { return 0; }
};
BOOST_FIXTURE_TEST_CASE(wallet_load_descriptors, TestingSetup)