@@ -165,7 +165,7 @@ struct PubkeyProvider
165
165
* write_cache is the cache to write keys to (if not nullptr)
166
166
* Caches are not exclusive but this is not tested. Currently we use them exclusively
167
167
*/
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;
169
169
170
170
/* * Whether this represent multiple public keys at different positions. */
171
171
virtual bool IsRange () const = 0;
@@ -195,7 +195,7 @@ class OriginPubkeyProvider final : public PubkeyProvider
195
195
196
196
public:
197
197
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
199
199
{
200
200
if (!m_provider->GetPubKey (pos, arg, key, info, read_cache, write_cache)) return false ;
201
201
std::copy (std::begin (m_origin.fingerprint ), std::end (m_origin.fingerprint ), info.fingerprint );
@@ -225,7 +225,7 @@ class ConstPubkeyProvider final : public PubkeyProvider
225
225
226
226
public:
227
227
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
229
229
{
230
230
key = m_pubkey;
231
231
info.path .clear ();
@@ -262,6 +262,9 @@ class BIP32PubkeyProvider final : public PubkeyProvider
262
262
CExtPubKey m_root_extkey;
263
263
KeyPath m_path;
264
264
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;
265
268
266
269
bool GetExtKey (const SigningProvider& arg, CExtKey& ret) const
267
270
{
@@ -298,7 +301,7 @@ class BIP32PubkeyProvider final : public PubkeyProvider
298
301
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) {}
299
302
bool IsRange () const override { return m_derive != DeriveType::NO; }
300
303
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
302
305
{
303
306
// Info of parent of the to be derived pubkey
304
307
KeyOriginInfo parent_info;
@@ -323,6 +326,9 @@ class BIP32PubkeyProvider final : public PubkeyProvider
323
326
final_extkey = parent_extkey;
324
327
if (m_derive == DeriveType::UNHARDENED) der = parent_extkey.Derive (final_extkey, pos);
325
328
}
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);
326
332
} else if (IsHardened ()) {
327
333
CExtKey xprv;
328
334
if (!GetDerivedExtKey (arg, xprv)) return false ;
@@ -344,6 +350,11 @@ class BIP32PubkeyProvider final : public PubkeyProvider
344
350
final_info_out = final_info_out_tmp;
345
351
key_out = final_extkey.pubkey ;
346
352
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
+
347
358
if (write_cache) {
348
359
// Only cache parent if there is any unhardened derivation
349
360
if (m_derive != DeriveType::HARDENED) {
0 commit comments