@@ -302,11 +302,14 @@ class BIP32PubkeyProvider final : public PubkeyProvider
302302 }
303303
304304 // Derives the last xprv
305- bool GetDerivedExtKey (const SigningProvider& arg, CExtKey& xprv) const
305+ bool GetDerivedExtKey (const SigningProvider& arg, CExtKey& xprv, CExtKey& last_hardened ) const
306306 {
307307 if (!GetExtKey (arg, xprv)) return false ;
308308 for (auto entry : m_path) {
309309 xprv.Derive (xprv, entry);
310+ if (entry >> 31 ) {
311+ last_hardened = xprv;
312+ }
310313 }
311314 return true ;
312315 }
@@ -340,6 +343,7 @@ class BIP32PubkeyProvider final : public PubkeyProvider
340343 // Derive keys or fetch them from cache
341344 CExtPubKey final_extkey = m_root_extkey;
342345 CExtPubKey parent_extkey = m_root_extkey;
346+ CExtPubKey last_hardened_extkey;
343347 bool der = true ;
344348 if (read_cache) {
345349 if (!read_cache->GetCachedDerivedExtPubKey (m_expr_index, pos, final_extkey)) {
@@ -351,11 +355,15 @@ class BIP32PubkeyProvider final : public PubkeyProvider
351355 }
352356 } else if (IsHardened ()) {
353357 CExtKey xprv;
354- if (!GetDerivedExtKey (arg, xprv)) return false ;
358+ CExtKey lh_xprv;
359+ if (!GetDerivedExtKey (arg, xprv, lh_xprv)) return false ;
355360 parent_extkey = xprv.Neuter ();
356361 if (m_derive == DeriveType::UNHARDENED) der = xprv.Derive (xprv, pos);
357362 if (m_derive == DeriveType::HARDENED) der = xprv.Derive (xprv, pos | 0x80000000UL );
358363 final_extkey = xprv.Neuter ();
364+ if (lh_xprv.key .IsValid ()) {
365+ last_hardened_extkey = lh_xprv.Neuter ();
366+ }
359367 } else {
360368 for (auto entry : m_path) {
361369 der = parent_extkey.Derive (parent_extkey, entry);
@@ -374,6 +382,10 @@ class BIP32PubkeyProvider final : public PubkeyProvider
374382 // Only cache parent if there is any unhardened derivation
375383 if (m_derive != DeriveType::HARDENED) {
376384 write_cache->CacheParentExtPubKey (m_expr_index, parent_extkey);
385+ // Cache last hardened xpub if we have it
386+ if (last_hardened_extkey.pubkey .IsValid ()) {
387+ write_cache->CacheLastHardenedExtPubKey (m_expr_index, last_hardened_extkey);
388+ }
377389 } else if (final_info_out.path .size () > 0 ) {
378390 write_cache->CacheDerivedExtPubKey (m_expr_index, pos, final_extkey);
379391 }
@@ -454,7 +466,8 @@ class BIP32PubkeyProvider final : public PubkeyProvider
454466 bool GetPrivKey (int pos, const SigningProvider& arg, CKey& key) const override
455467 {
456468 CExtKey extkey;
457- if (!GetDerivedExtKey (arg, extkey)) return false ;
469+ CExtKey dummy;
470+ if (!GetDerivedExtKey (arg, extkey, dummy)) return false ;
458471 if (m_derive == DeriveType::UNHARDENED) extkey.Derive (extkey, pos);
459472 if (m_derive == DeriveType::HARDENED) extkey.Derive (extkey, pos | 0x80000000UL );
460473 key = extkey.key ;
@@ -1400,6 +1413,11 @@ void DescriptorCache::CacheDerivedExtPubKey(uint32_t key_exp_pos, uint32_t der_i
14001413 xpubs[der_index] = xpub;
14011414}
14021415
1416+ void DescriptorCache::CacheLastHardenedExtPubKey (uint32_t key_exp_pos, const CExtPubKey& xpub)
1417+ {
1418+ m_last_hardened_xpubs[key_exp_pos] = xpub;
1419+ }
1420+
14031421bool DescriptorCache::GetCachedParentExtPubKey (uint32_t key_exp_pos, CExtPubKey& xpub) const
14041422{
14051423 const auto & it = m_parent_xpubs.find (key_exp_pos);
@@ -1418,6 +1436,14 @@ bool DescriptorCache::GetCachedDerivedExtPubKey(uint32_t key_exp_pos, uint32_t d
14181436 return true ;
14191437}
14201438
1439+ bool DescriptorCache::GetCachedLastHardenedExtPubKey (uint32_t key_exp_pos, CExtPubKey& xpub) const
1440+ {
1441+ const auto & it = m_last_hardened_xpubs.find (key_exp_pos);
1442+ if (it == m_last_hardened_xpubs.end ()) return false ;
1443+ xpub = it->second ;
1444+ return true ;
1445+ }
1446+
14211447DescriptorCache DescriptorCache::MergeAndDiff (const DescriptorCache& other)
14221448{
14231449 DescriptorCache diff;
@@ -1445,6 +1471,17 @@ DescriptorCache DescriptorCache::MergeAndDiff(const DescriptorCache& other)
14451471 diff.CacheDerivedExtPubKey (derived_xpub_map_pair.first , derived_xpub_pair.first , derived_xpub_pair.second );
14461472 }
14471473 }
1474+ for (const auto & lh_xpub_pair : other.GetCachedLastHardenedExtPubKeys ()) {
1475+ CExtPubKey xpub;
1476+ if (GetCachedLastHardenedExtPubKey (lh_xpub_pair.first , xpub)) {
1477+ if (xpub != lh_xpub_pair.second ) {
1478+ throw std::runtime_error (std::string (__func__) + " : New cached last hardened xpub does not match already cached last hardened xpub" );
1479+ }
1480+ continue ;
1481+ }
1482+ CacheLastHardenedExtPubKey (lh_xpub_pair.first , lh_xpub_pair.second );
1483+ diff.CacheLastHardenedExtPubKey (lh_xpub_pair.first , lh_xpub_pair.second );
1484+ }
14481485 return diff;
14491486}
14501487
@@ -1457,3 +1494,8 @@ const std::unordered_map<uint32_t, ExtPubKeyMap> DescriptorCache::GetCachedDeriv
14571494{
14581495 return m_derived_xpubs;
14591496}
1497+
1498+ const ExtPubKeyMap DescriptorCache::GetCachedLastHardenedExtPubKeys () const
1499+ {
1500+ return m_last_hardened_xpubs;
1501+ }
0 commit comments