Skip to content

Commit 09e2507

Browse files
committed
Cache parent xpub inside of BIP32PubkeyProvider
Optimize Expand by having BIP32PubkeyProvider also cache the parent (or only) xpub within itself. Since Expand does not provide a read cache, it is useful to internally cache this xpub to avoid re-deriving the same xpub.
1 parent deb791c commit 09e2507

File tree

1 file changed

+15
-4
lines changed

1 file changed

+15
-4
lines changed

src/script/descriptor.cpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ struct PubkeyProvider
165165
* write_cache is the cache to write keys to (if not nullptr)
166166
* Caches are not exclusive but this is not tested. Currently we use them exclusively
167167
*/
168-
virtual bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) const = 0;
168+
virtual bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) = 0;
169169

170170
/** Whether this represent multiple public keys at different positions. */
171171
virtual bool IsRange() const = 0;
@@ -195,7 +195,7 @@ class OriginPubkeyProvider final : public PubkeyProvider
195195

196196
public:
197197
OriginPubkeyProvider(uint32_t exp_index, KeyOriginInfo info, std::unique_ptr<PubkeyProvider> provider) : PubkeyProvider(exp_index), m_origin(std::move(info)), m_provider(std::move(provider)) {}
198-
bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) const override
198+
bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) override
199199
{
200200
if (!m_provider->GetPubKey(pos, arg, key, info, read_cache, write_cache)) return false;
201201
std::copy(std::begin(m_origin.fingerprint), std::end(m_origin.fingerprint), info.fingerprint);
@@ -225,7 +225,7 @@ class ConstPubkeyProvider final : public PubkeyProvider
225225

226226
public:
227227
ConstPubkeyProvider(uint32_t exp_index, const CPubKey& pubkey) : PubkeyProvider(exp_index), m_pubkey(pubkey) {}
228-
bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) const override
228+
bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) override
229229
{
230230
key = m_pubkey;
231231
info.path.clear();
@@ -262,6 +262,9 @@ class BIP32PubkeyProvider final : public PubkeyProvider
262262
CExtPubKey m_root_extkey;
263263
KeyPath m_path;
264264
DeriveType m_derive;
265+
// Cache of the parent of the final derived pubkeys.
266+
// Primarily useful for situations when no read_cache is provided
267+
CExtPubKey m_cached_xpub;
265268

266269
bool GetExtKey(const SigningProvider& arg, CExtKey& ret) const
267270
{
@@ -298,7 +301,7 @@ class BIP32PubkeyProvider final : public PubkeyProvider
298301
BIP32PubkeyProvider(uint32_t exp_index, const CExtPubKey& extkey, KeyPath path, DeriveType derive) : PubkeyProvider(exp_index), m_root_extkey(extkey), m_path(std::move(path)), m_derive(derive) {}
299302
bool IsRange() const override { return m_derive != DeriveType::NO; }
300303
size_t GetSize() const override { return 33; }
301-
bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key_out, KeyOriginInfo& final_info_out, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) const override
304+
bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key_out, KeyOriginInfo& final_info_out, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) override
302305
{
303306
// Info of parent of the to be derived pubkey
304307
KeyOriginInfo parent_info;
@@ -323,6 +326,9 @@ class BIP32PubkeyProvider final : public PubkeyProvider
323326
final_extkey = parent_extkey;
324327
if (m_derive == DeriveType::UNHARDENED) der = parent_extkey.Derive(final_extkey, pos);
325328
}
329+
} else if (m_cached_xpub.pubkey.IsValid() && m_derive != DeriveType::HARDENED) {
330+
parent_extkey = final_extkey = m_cached_xpub;
331+
if (m_derive == DeriveType::UNHARDENED) der = parent_extkey.Derive(final_extkey, pos);
326332
} else if (IsHardened()) {
327333
CExtKey xprv;
328334
if (!GetDerivedExtKey(arg, xprv)) return false;
@@ -344,6 +350,11 @@ class BIP32PubkeyProvider final : public PubkeyProvider
344350
final_info_out = final_info_out_tmp;
345351
key_out = final_extkey.pubkey;
346352

353+
// We rely on the consumer to check that m_derive isn't HARDENED as above
354+
// But we can't have already cached something in case we read something from the cache
355+
// and parent_extkey isn't actually the parent.
356+
if (!m_cached_xpub.pubkey.IsValid()) m_cached_xpub = parent_extkey;
357+
347358
if (write_cache) {
348359
// Only cache parent if there is any unhardened derivation
349360
if (m_derive != DeriveType::HARDENED) {

0 commit comments

Comments
 (0)