mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-06-05 18:52:29 +02:00
Merge #14646: Add expansion cache functions to descriptors (unused for now)
26879509fAdd comments to descriptor tests (Pieter Wuille)82df4c64fAdd descriptor expansion cache (Pieter Wuille)1eda33aab[refactor] Combine the ToString and ToPrivateString implementations (Pieter Wuille)24d3a7b3a[refactor] Use DescriptorImpl internally, permitting access to new methods (Pieter Wuille)6be0fb4b3[refactor] Add a base DescriptorImpl with most common logic (Pieter Wuille) Pull request description: This patch modifies the internal `Descriptor` class to optionally construct and use an "expansion cache". Such a cache is a byte array that encodes all information necessary to expand a `Descriptor` a second time without access to private keys, and without the need to perform expensive BIP32 derivations. For all currently defined descriptors, the cache simply contains a concatenation of all public keys used. This is motivated by the goal of importing a descriptor into the wallet and using it as a replacement for the keypool, where it would be impossible to expand descriptors if they use hardened derivation. Tree-SHA512: f531a0a82ec1eecc30b78ba8a31724d1249826b028cc3543ad32372e1aedd537f137ab03dbffc222c5df444d5865ecd5cec754c1ae1d4989b6e9baeaffade32a
This commit is contained in:
@@ -79,19 +79,42 @@ void Check(const std::string& prv, const std::string& pub, int flags, const std:
|
||||
BOOST_CHECK_EQUAL(parse_pub->IsRange(), (flags & RANGE) != 0);
|
||||
BOOST_CHECK_EQUAL(parse_priv->IsRange(), (flags & RANGE) != 0);
|
||||
|
||||
|
||||
// Is not ranged descriptor, only a single result is expected.
|
||||
// * 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
|
||||
// each element in `scripts`.
|
||||
// * For non-ranged descriptors, we evaluate the descriptors at positions 0, 1, and 2, but expect the
|
||||
// same result in each case, namely the first element of `scripts`. Because of that, the size of
|
||||
// `scripts` must be one in that case.
|
||||
if (!(flags & RANGE)) assert(scripts.size() == 1);
|
||||
|
||||
size_t max = (flags & RANGE) ? scripts.size() : 3;
|
||||
|
||||
// Iterate over the position we'll evaluate the descriptors in.
|
||||
for (size_t i = 0; i < max; ++i) {
|
||||
// Call the expected result scripts `ref`.
|
||||
const auto& ref = scripts[(flags & RANGE) ? i : 0];
|
||||
// When t=0, evaluate the `prv` descriptor; when t=1, evaluate the `pub` descriptor.
|
||||
for (int t = 0; t < 2; ++t) {
|
||||
// When the descriptor is hardened, evaluate with access to the private keys inside.
|
||||
const FlatSigningProvider& key_provider = (flags & HARDENED) ? keys_priv : keys_pub;
|
||||
FlatSigningProvider script_provider;
|
||||
std::vector<CScript> spks;
|
||||
BOOST_CHECK((t ? parse_priv : parse_pub)->Expand(i, key_provider, spks, script_provider));
|
||||
|
||||
// Evaluate the descriptor selected by `t` in poisition `i`.
|
||||
FlatSigningProvider script_provider, script_provider_cached;
|
||||
std::vector<CScript> spks, spks_cached;
|
||||
std::vector<unsigned char> cache;
|
||||
BOOST_CHECK((t ? parse_priv : parse_pub)->Expand(i, key_provider, spks, script_provider, &cache));
|
||||
|
||||
// Compare the output with the expected result.
|
||||
BOOST_CHECK_EQUAL(spks.size(), ref.size());
|
||||
|
||||
// Try to expand again using cached data, and compare.
|
||||
BOOST_CHECK(parse_pub->ExpandFromCache(i, cache, spks_cached, script_provider_cached));
|
||||
BOOST_CHECK(spks == spks_cached);
|
||||
BOOST_CHECK(script_provider.pubkeys == script_provider_cached.pubkeys);
|
||||
BOOST_CHECK(script_provider.scripts == script_provider_cached.scripts);
|
||||
BOOST_CHECK(script_provider.origins == script_provider_cached.origins);
|
||||
|
||||
// For each of the produced scripts, verify solvability, and when possible, try to sign a transaction spending it.
|
||||
for (size_t n = 0; n < spks.size(); ++n) {
|
||||
BOOST_CHECK_EQUAL(ref[n], HexStr(spks[n].begin(), spks[n].end()));
|
||||
BOOST_CHECK_EQUAL(IsSolvable(Merge(key_provider, script_provider), spks[n]), (flags & UNSOLVABLE) == 0);
|
||||
@@ -123,6 +146,7 @@ void Check(const std::string& prv, const std::string& pub, int flags, const std:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Verify no expected paths remain that were not observed.
|
||||
BOOST_CHECK_MESSAGE(left_paths.empty(), "Not all expected key paths found: " + prv);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user