From 1972efd037770880c5d723adc8b94a08a3aba264 Mon Sep 17 00:00:00 2001 From: Omar Date: Sat, 3 Oct 2026 02:17:49 +0200 Subject: [PATCH] only check address validation once for old addresses --- cw_bitcoin/lib/bitcoin_address_record.dart | 7 +++ cw_bitcoin/lib/electrum_wallet_addresses.dart | 46 +++++++++---------- .../lib/src/bitcoin_cash_wallet.dart | 2 + 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/cw_bitcoin/lib/bitcoin_address_record.dart b/cw_bitcoin/lib/bitcoin_address_record.dart index a08801234..a06034caf 100644 --- a/cw_bitcoin/lib/bitcoin_address_record.dart +++ b/cw_bitcoin/lib/bitcoin_address_record.dart @@ -67,6 +67,7 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord { required super.index, super.accountIndex = 0, super.isHidden = false, + this.isHiddenChecked = false, super.isLegacyDerivation = false, super.txCount = 0, super.balance = 0, @@ -110,6 +111,7 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord { index: decoded['index'] as int, accountIndex: decoded['accountIndex'] as int? ?? 0, isHidden: decoded['isHidden'] as bool? ?? false, + isHiddenChecked: decoded['isHiddenChecked'] as bool? ?? false, isLegacyDerivation: parsedIsLegacy, isUsed: decoded['isUsed'] as bool? ?? false, txCount: decoded['txCount'] as int? ?? 0, @@ -121,6 +123,10 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord { ); } + /// Whether [isHidden] has been checked against the wallet's keys. Records created from the + /// wallet's own keys are correct by construction; older ones are checked once on wallet open. + bool isHiddenChecked; + String? scriptHash; static int _purposeForType(BitcoinAddressType type) { @@ -179,6 +185,7 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord { 'index': index, 'accountIndex': accountIndex, 'isHidden': isHidden, + 'isHiddenChecked': isHiddenChecked, 'isLegacyDerivation': isLegacyDerivation, 'isUsed': isUsed, 'txCount': txCount, diff --git a/cw_bitcoin/lib/electrum_wallet_addresses.dart b/cw_bitcoin/lib/electrum_wallet_addresses.dart index b5559ab10..2779e2ad0 100644 --- a/cw_bitcoin/lib/electrum_wallet_addresses.dart +++ b/cw_bitcoin/lib/electrum_wallet_addresses.dart @@ -571,6 +571,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { index: newAddressIndex, accountIndex: accountIndex, isHidden: false, + isHiddenChecked: true, isLegacyDerivation: false, name: label, type: addressPageType, @@ -957,6 +958,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { await getAddressAsync(index: i, hd: hd, addressType: addrType), index: i, isHidden: isHidden, + isHiddenChecked: true, isLegacyDerivation: isLegacyDerivation, type: addrType, network: network, @@ -1023,37 +1025,31 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { } Future _validateAddress(BitcoinAddressRecord element) async { + if (element.isHiddenChecked) return; + if (element.type == SegwitAddresType.mweb) { // this would add a ton of startup lag for mweb addresses since we have 1000 of them return; } - try { - final mainHd = _hdForAddressGeneration( - isHidden: false, - type: element.type, - isLegacyDerivation: element.isLegacyDerivation, - accountIndex: element.accountIndex); - final sideHd = _hdForAddressGeneration( - isHidden: true, - type: element.type, - isLegacyDerivation: element.isLegacyDerivation, - accountIndex: element.accountIndex); - if (!element.isHidden && - element.address != - await getAddressAsync( - index: element.index, hd: mainHd, addressType: element.type)) { - element.isHidden = true; - } else if (element.isHidden && - element.address != - await getAddressAsync( - index: element.index, hd: sideHd, addressType: element.type)) { - element.isHidden = false; - } - } on UnsupportedAddressTypeForAccountException catch (e) { - printV("_validateAddresses: skipping ${element.address}: $e"); + try { + // Relabel only when the address re-derives from the other chain. A record from a path these + // keys don't produce matches neither chain, so it keeps its label instead of flipping. + final otherChainHd = _hdForAddressGeneration( + isHidden: !element.isHidden, + type: element.type, + isLegacyDerivation: element.isLegacyDerivation, + accountIndex: element.accountIndex, + ); + final otherChainAddress = + await getAddressAsync(index: element.index, hd: otherChainHd, addressType: element.type); + if (element.address == otherChainAddress) { + element.isHidden = !element.isHidden; } - }); + element.isHiddenChecked = true; + } on UnsupportedAddressTypeForAccountException catch (e) { + printV("_validateAddresses: skipping ${element.address}: $e"); + } } @override diff --git a/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet.dart b/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet.dart index f05aaa845..2f4a4dc49 100644 --- a/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet.dart +++ b/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet.dart @@ -150,6 +150,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store { addr.address, index: addr.index, isHidden: addr.isHidden, + isHiddenChecked: addr.isHiddenChecked, name: addr.name, type: P2pkhAddressType.p2pkh, network: BitcoinCashNetwork.mainnet, @@ -159,6 +160,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store { AddressUtils.getCashAddrFormat(addr.address), index: addr.index, isHidden: addr.isHidden, + isHiddenChecked: addr.isHiddenChecked, name: addr.name, type: P2pkhAddressType.p2pkh, network: BitcoinCashNetwork.mainnet,