From 8f54a883fab5d5e597ed1456099b78a111a29184 Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Fri, 19 Dec 2025 14:14:02 +0300 Subject: [PATCH] fix: only activate BIP44 descriptors for external signers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When creating a wallet with an external signer (hardware wallet), the mock signer returns multiple descriptors (BIP44, BIP49, BIP84) for both receive and internal categories. Previously, all valid descriptors were being activated by calling AddActiveScriptPubKeyMan() for each one. This caused a database key collision since multiple descriptors tried to write to the same key (ACTIVEEXTERNALSPK or ACTIVEINTERNALSPK), resulting in non-deterministic behavior where sometimes BIP44 would be active and sometimes BIP84, depending on database flush timing. The fix follows the pattern from the non-external-signer branch which stores multiple descriptors but only activates certain types (External and Internal, but not CoinJoin). Now we: - Store ALL descriptors returned by the signer in m_spk_managers - Only activate descriptors matching the BIP44 path pattern /44'/{cointype}' This ensures deterministic behavior and fixes the intermittent test failure in wallet_signer.py where the test expected m/44' but sometimes got m/84'. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- src/wallet/wallet.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 85adcf5ad527..bf0218983243 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3926,7 +3926,12 @@ void CWallet::SetupDescriptorScriptPubKeyMans(const SecureString& mnemonic_arg, spk_manager->SetupDescriptor(std::move(desc)); uint256 id = spk_manager->GetID(); m_spk_managers[id] = std::move(spk_manager); - AddActiveScriptPubKeyMan(id, internal); + // Only activate BIP44 descriptors, similar to how the non-external-signer branch + // only activates certain types (External and Internal, but not CoinJoin) + std::string bip44_purpose = strprintf("/%d'/%s'", BIP32_PURPOSE_STANDARD, Params().ExtCoinType()); + if (desc_str.find(bip44_purpose) != std::string::npos) { + AddActiveScriptPubKeyMan(id, internal); + } } } }