diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -440,10 +440,12 @@ key_out = final_extkey.pubkey; if (write_cache) { - write_cache->CacheDerivedExtPubKey(m_expr_index, pos, final_extkey); // Only cache parent if there is any unhardened derivation if (m_derive != DeriveType::HARDENED) { write_cache->CacheParentExtPubKey(m_expr_index, parent_extkey); + } else if (final_info_out.path.size() > 0) { + write_cache->CacheDerivedExtPubKey(m_expr_index, pos, + final_extkey); } } diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp --- a/src/test/descriptor_tests.cpp +++ b/src/test/descriptor_tests.cpp @@ -181,6 +181,60 @@ BOOST_CHECK(script_provider.origins == script_provider_cached.origins); + // Check whether keys are in the cache + const auto &der_xpub_cache = + desc_cache.GetCachedDerivedExtPubKeys(); + const auto &parent_xpub_cache = + desc_cache.GetCachedParentExtPubKeys(); + if ((flags & RANGE) && !(flags & DERIVE_HARDENED)) { + // For ranged, unhardened derivation, None of the keys in + // origins should appear in the cache but the cache should have + // parent keys But we can derive one level from each of those + // parent keys and find them all + BOOST_CHECK(der_xpub_cache.empty()); + BOOST_CHECK(parent_xpub_cache.size() > 0); + std::set pubkeys; + for (const auto &xpub_pair : parent_xpub_cache) { + const CExtPubKey &xpub = xpub_pair.second; + CExtPubKey der; + xpub.Derive(der, i); + pubkeys.insert(der.pubkey); + } + for (const auto &origin_pair : script_provider_cached.origins) { + const CPubKey &pk = origin_pair.second.first; + BOOST_CHECK(pubkeys.count(pk) > 0); + } + } else if (pub1.find("xpub") != std::string::npos) { + // For ranged, hardened derivation, or not ranged, but has an + // xpub, all of the keys should appear in the cache + BOOST_CHECK(der_xpub_cache.size() + parent_xpub_cache.size() == + script_provider_cached.origins.size()); + // Get all of the derived pubkeys + std::set pubkeys; + for (const auto &xpub_map_pair : der_xpub_cache) { + for (const auto &xpub_pair : xpub_map_pair.second) { + const CExtPubKey &xpub = xpub_pair.second; + pubkeys.insert(xpub.pubkey); + } + } + // Derive one level from all of the parents + for (const auto &xpub_pair : parent_xpub_cache) { + const CExtPubKey &xpub = xpub_pair.second; + pubkeys.insert(xpub.pubkey); + CExtPubKey der; + xpub.Derive(der, i); + pubkeys.insert(der.pubkey); + } + for (const auto &origin_pair : script_provider_cached.origins) { + const CPubKey &pk = origin_pair.second.first; + BOOST_CHECK(pubkeys.count(pk) > 0); + } + } else { + // No xpub, nothing should be cached + BOOST_CHECK(der_xpub_cache.empty()); + BOOST_CHECK(parent_xpub_cache.empty()); + } + // Make sure we can expand using cached xpubs for unhardened // derivation if (!(flags & DERIVE_HARDENED)) {