diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index dad8aef39dc..0759e2d5220 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -628,19 +628,28 @@ std::optional LegacyDataSPKM::MigrateToDescriptor() bool can_support_hd_split_feature = m_hd_chain.nVersion >= CHDChain::VERSION_HD_CHAIN_SPLIT; + std::set master_xpubs; for (const CHDChain& chain : chains) { + if (chain.seed_id.IsNull()) continue; + + // Get the master xprv + CKey seed_key; + if (!GetKey(chain.seed_id, seed_key)) { + assert(false); + } + CExtKey master_key; + master_key.SetSeed(seed_key); + + // Get the xpub and verify that we haven't already seen this xpub before + CExtPubKey master_xpub = master_key.Neuter(); + const auto& [_, inserted] = master_xpubs.insert(master_xpub); + if (!inserted) continue; + for (int i = 0; i < 2; ++i) { // Skip if doing internal chain and split chain is not supported - if (chain.seed_id.IsNull() || (i == 1 && !can_support_hd_split_feature)) { + if (i == 1 && !can_support_hd_split_feature) { continue; } - // Get the master xprv - CKey seed_key; - if (!GetKey(chain.seed_id, seed_key)) { - assert(false); - } - CExtKey master_key; - master_key.SetSeed(seed_key); // Make the combo descriptor std::string xpub = EncodeExtPubKey(master_key.Neuter()); diff --git a/src/wallet/test/fuzz/scriptpubkeyman.cpp b/src/wallet/test/fuzz/scriptpubkeyman.cpp index b6b3c5d5597..bb848d1c9dd 100644 --- a/src/wallet/test/fuzz/scriptpubkeyman.cpp +++ b/src/wallet/test/fuzz/scriptpubkeyman.cpp @@ -257,10 +257,10 @@ FUZZ_TARGET(spkm_migration, .init = initialize_spkm_migration) bool add_inactive_hd_chain{fuzzed_data_provider.ConsumeBool() && !keys.empty()}; if (add_inactive_hd_chain) { - hd_key = PickValue(fuzzed_data_provider, keys); + CKey inactive_hd_key = PickValue(fuzzed_data_provider, keys); hd_chain.nVersion = fuzzed_data_provider.ConsumeBool() ? CHDChain::VERSION_HD_CHAIN_SPLIT : CHDChain::VERSION_HD_BASE; - bool dup_chain = hd_chain.seed_id == hd_key.GetPubKey().GetID(); - hd_chain.seed_id = hd_key.GetPubKey().GetID(); + bool dup_chain = hd_key.IsValid() && std::equal(hd_key.begin(), hd_key.end(), inactive_hd_key.begin()); + hd_chain.seed_id = inactive_hd_key.GetPubKey().GetID(); legacy_data.AddInactiveHDChain(hd_chain); if (!dup_chain) added_chains++; }